構建本身的PHP框架--構建緩存組件(2)

上一篇博客中使用文件實現了緩存組件,這一篇咱們就使用Redis來實現一下,剩下的如何使用memcache、mysql等去實現緩存我就不一一去作了。php

首先咱們須要安裝一下 redis 和 phpredis 庫,phpredis 項目在github上的地址:https://github.com/phpredis/phpredis 。相應的文檔也在上面。mysql

先在 src/cache 文件夾下建立 RedisCache.php 文件。在寫組件的時候發現咱們缺乏一個地方去建立一個 Redis 的實例,而且是在建立 cahce 實例以後,返回給Yii::createObject 方法以前。因此咱們修改了 src/Sf.php 文件,其 createObject 方法的內容以下:git

public static function createObject($name)
    {
        $config = require(SF_PATH . "/config/$name.php");
        // create instance
        $instance = new $config['class']();
        unset($config['class']);
        // add attributes
        foreach ($config as $key => $value) {
            $instance->$key = $value;
        }
        $instance->init();
        return $instance;
    }

對比以前的代碼,不難發現其實只添加了一行 $instance->init(); ,這樣咱們就能夠在 init 方法中去建立相應的 Redis 實例,並保存下來。但這樣又會引入一個問題,全部使用 Yii::createObject 建立的實例都必須含有 init 方法(固然你也能夠判斷有沒有這個方法)。那咱們就來實現一個基礎類 Component ,並規定全部使用 Yii::createObject 建立的實例都集成它,而後再在 Component 中加入 init 方法便可。github

爲何選擇這種作法,而不是使用判斷 init 方法存不存在的方式去解決這個問題,主要是考慮到以後可能還須要對這些類作一些公共的事情,就提早抽出了 Component 類。redis

Component 類如今很簡單,其內容以下:sql

<?php
namespace sf\base;

/**
 * Component is the base class for most sf classes.
 * @author Harry Sun <sunguangjun@126.com>
 */
class Component
{
    /**
     * Initializes the component.
     * This method is invoked at the end of the constructor after the object is initialized with the
     * given configuration.
     */
    public function init()
    {
    }
}

以後再定義一下 Redis 緩存的配置以下:json

<?php
return [
    'class' => 'sf\cache\RedisCache',
    'redis' => [
        'host' => 'localhost',
        'port' => 6379,
        'database' => 0,
        // 'password' =>'jun',
        // 'options' => [Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP],
    ]
];

其中 password 和 options 是選填,其它是必填。緩存

剩下的就是相關實現,就不一一細說了,代碼以下:ide

<?php
namespace sf\cache;

use Redis;
use Exception;
use sf\base\Component;

/**
 * CacheInterface
 * @author Harry Sun <sunguangjun@126.com>
 */
class RedisCache extends Component implements CacheInterface
{
    /**
     * @var Redis|array the Redis object or the config of redis
     */
    public $redis;

    public function init()
    {
        if (is_array($this->redis)) {
            extract($this->redis);
            $redis = new Redis();
            $redis->connect($host, $port);
            if (!empty($password)) {
                $redis->auth($password);
            }
            $redis->select($database);
            if (!empty($options)) {
                call_user_func_array([$redis, 'setOption'], $options);
            }
            $this->redis = $redis;
        }
        if (!$this->redis instanceof Redis) {
            throw new Exception('Cache::redis must be either a Redis connection instance.');
        }
    }
    /**
     * Builds a normalized cache key from a given key.
     */
    public function buildKey($key)
    {
        if (!is_string($key)) {
            $key = json_encode($key);
        }
        return md5($key);
    }

    /**
     * Retrieves a value from cache with a specified key.
     */
    public function get($key)
    {
        $key = $this->buildKey($key);
        return $this->redis->get($key);
    }

    /**
     * Checks whether a specified key exists in the cache.
     */
    public function exists($key)
    {
        $key = $this->buildKey($key);
        return $this->redis->exists($key);
    }

    /**
     * Retrieves multiple values from cache with the specified keys.
     */
    public function mget($keys)
    {
        for ($index = 0; $index < count($keys); $index++) {
            $keys[$index] = $this->buildKey($keys[$index]);
        }

        return $this->redis->mGet($keys);
    }

    /**
     * Stores a value identified by a key into cache.
     */
    public function set($key, $value, $duration = 0)
    {
        $key = $this->buildKey($key);
        if ($duration !== 0) {
            $expire = (int) $duration * 1000;
            return $this->redis->set($key, $value, $expire);
        } else {
            return $this->redis->set($key, $value);
        }
    }

    /**
     * Stores multiple items in cache. Each item contains a value identified by a key.
     */
    public function mset($items, $duration = 0)
    {
        $failedKeys = [];
        foreach ($items as $key => $value) {
            if ($this->set($key, $value, $duration) === false) {
                $failedKeys[] = $key;
            }
        }

        return $failedKeys;
    }

    /**
     * Stores a value identified by a key into cache if the cache does not contain this key.
     */
    public function add($key, $value, $duration = 0)
    {
        if (!$this->exists($key)) {
            return $this->set($key, $value, $duration);
        } else {
            return false;
        }
    }

    /**
     * Stores multiple items in cache. Each item contains a value identified by a key.
     */
    public function madd($items, $duration = 0)
    {
        $failedKeys = [];
        foreach ($items as $key => $value) {
            if ($this->add($key, $value, $duration) === false) {
                $failedKeys[] = $key;
            }
        }

        return $failedKeys;
    }

    /**
     * Deletes a value with the specified key from cache
     */
    public function delete($key)
    {
        $key = $this->buildKey($key);
        return $this->redis->delete($key);
    }

    /**
     * Deletes all values from cache.
     */
    public function flush()
    {
        return $this->redis->flushDb();
    }
}

訪問 http://localhost/simple-framework/public/index.php?r=site/cache 路徑,獲得結果以下:測試

我就是測試一下緩存組件

這樣咱們完成了使用 Redis 的緩存組件。

好了,今天就先到這裏。項目內容和博客內容也都會放到Github上,歡迎你們提建議。

code:https://github.com/CraryPrimitiveMan/simple-framework/tree/1.0

blog project:https://github.com/CraryPrimitiveMan/create-your-own-php-framework

相關文章
相關標籤/搜索