TP5之Cache的原理及使用

來源:互聯網
上載者:User
在當今大流量的互連網之中,Cache的重要性不言而喻。ThinkPhp5作為國內主流架構,提供了強大的Cache功能。讓我們跟隨本文,來剖析TP5 Cache的原理及使用。

為什麼需要Cache(緩衝)?

假設現在有一個小說網,有非常多的讀者,有一篇新的章節更新了,那麼可能一分鐘內有幾萬幾十萬的訪問量.

如果沒有緩衝,同樣的內容就要去資料庫重複查詢,那可能網站一下就掛掉了.

追求效能的web網站應該充分利用緩衝,常見的緩衝類型有File,Memcache,Redis等,這裡就不說他們的區別了

今天我們分析下TP5 Cache的內部實現原理.

首先看官方文檔如何使用緩衝的.

如,調用Cache類的的靜態方法set就可以直接使用了,我們查看Cache類檔案 在application/thinkphp/library/think目錄下

   protected static $instance = [];       public static $readTimes   = 0;       public static $writeTimes  = 0;      /**     * 操作控制代碼     * @var object     * @access protected     */    protected static $handler;     /**     * 寫入緩衝     * @access public     * @param string        $name 緩衝標識     * @param mixed         $value  儲存資料     * @param int|null      $expire  有效時間 0為永久     * @return boolean     */    public static function set($name, $value, $expire = null)    {        self::$writeTimes++;                return self::init()->set($name, $value, $expire);    }

看到原來set方法是這樣的, 其中writeTimes 是Cache類的靜態變數,主要記錄緩衝的讀取次數,這不是重點.

注意到了嗎,有個靜態變數命名為 $instance, 上次說過這樣命名大機率就是 單例模式了.

set方法的重點是init方法

我們再看init方法

  public static function init(array $options = [])    {        if (is_null(self::$handler)) {            // 自動初始化緩衝            if (!empty($options)) {                            $connect = self::connect($options);            } elseif ('complex' == Config::get('cache.type')) {                            $connect = self::connect(Config::get('cache.default'));            } else {                            $connect = self::connect(Config::get('cache'));            }            self::$handler = $connect;        }        return self::$handler;    }

handler就是操作的控制代碼(巨餅:-) ), 這裡一看,果然是單例模式了,如果控制代碼為空白才去初始化對象,不然直接返回.控制代碼

同樣,這裡重點是connect函數, 傳入的參數是 配置資訊

同樣,我們查看connect方法

/**     * 串連緩衝     * @access public     * @param array         $options  配置數組     * @param bool|string   $name 緩衝串連標識 true 強制重新串連     * @return Driver     */    public static function connect(array $options = [], $name = false)    {        $type = !empty($options['type']) ? $options['type'] : 'File';        if (false === $name) {            $name = md5(serialize($options));        }        if (true === $name || !isset(self::$instance[$name])) {            $class = false !== strpos($type, '\\') ? $type : '\\think\\cache\\driver\\' . ucwords($type);            // 記錄初始化資訊            App::$debug && Log::record('[ CACHE ] INIT ' . $type, 'info');            if (true === $name) {                return new $class($options);            } else {                self::$instance[$name] = new $class($options);            }        }        return self::$instance[$name];    }

self::$instance[$name] = new $class($options); 這一句裡,我們就可以知道控制代碼的真實身份拉,
$class = false !== strpos($type, '\\') ? $type : '\\think\\cache\\driver\\' . ucwords($type);
這一句的意思是class的名字由type決定, 如果type沒有包含反斜線, 則class = \think\cache\driver\.ucwords($type)
thinkPhp 是把think作為核心目錄的別名的,所以他真實路徑就是 \thinkphp\libray\\think\driver\.ucwords($type)
根據自動載入的尿性,自然是去該檔案夾下載入對應的對象
 (額外提一句,這利用的是PHP動態變數的一個特性,其實就和原廠模式一個原理,運行中動態決定執行個體化的對象)
 type是什麼呢? type就是函數傳入的參數,也就是配置資訊,我們看下配置資訊
type就是驅動方式,如果我們type填寫的是File,那麼就使用檔案驅動,執行個體化的是 \think\cache\driver\File.class
我們看下 \think\cache\driver檔案下有什麼檔案,那就知道thinkphp為我們提供了多少種緩衝驅動了

原來有這麼多!

點進去

每個檔案,我們可以發現一個共同點, 每個類都是繼承了 抽象類別 Driver

Driver決定了 每一個Cache驅動應該是什麼樣子的,他們的方法基本是一樣的,而實現方式因每個驅動不同而異

其實這就是 適配器模式,如果是我們自己寫,當然不會寫那麼多拉,不過TP5是為了造福廣大PHP開發人員,所以編寫了那麼多不同的驅動供我們使用.

我們重點看Redis吧, 如果要去實驗,記得把 config中的 Cache.type更改為 redis

Redis類的方法很少,先看看建構函式

public function __construct($options = [])    {        if (!extension_loaded('redis')) {            throw new \BadFunctionCallException('not support: redis');        }        if (!empty($options)) {            $this->options = array_merge($this->options, $options);        }        $func          = $this->options['persistent'] ? 'pconnect' : 'connect';        $this->handler = new \Redis;        $this->handler->$func($this->options['host'], $this->options['port'], $this->options['timeout']);        if ('' != $this->options['password']) {            $this->handler->auth($this->options['password']);        }        if (0 != $this->options['select']) {            $this->handler->select($this->options['select']);        }    }

可見TP5的 redis驅動 是基於phpredis的阿, handler 就是執行個體化的phpredis類, 因此選了哪個驅動,Cache的類自然就是哪些驅動.
所以說如果要使用 TP5的 redis,必須要先安裝phpredis擴充.
這裡就順便解析下 redis重寫的 set方法

/**     * 寫入緩衝     * @access public     * @param string    $name 緩衝變數名     * @param mixed     $value  儲存資料     * @param integer   $expire  有效時間(秒)     * @return boolean     */    public function set($name, $value, $expire = null)    {        if (is_null($expire)) {            $expire = $this->options['expire'];        }        if ($this->tag && !$this->has($name)) {            $first = true;        }        $key = $this->getCacheKey($name);        //對數組/對象資料進行緩衝處理,保證資料完整性  byron sampson<xiaobo.sun@qq.com>        $value = (is_object($value) || is_array($value)) ? json_encode($value) : $value;        if (is_int($expire) && $expire) {            $result = $this->handler->setex($key, $expire, $value);        } else {            $result = $this->handler->set($key, $value);        }        isset($first) && $this->setTagItem($key);        return $result;    }

原本的phpredis set方法 只能是 普通的索引值對, 而重寫的set方法現在可以是 鍵,數組啦,這是非常有用的方法

可以看到實現的 原理是把 數組或者對象 序列化為json, 取值的時候則還原序列化成為數組.

到這裡我們就基本分析完了一個驅動是如何?的,首先必須 繼承Driver類,實現Driver規定的方法,然後將handler交給Cache類去使用

我們回到Cache類

可以看到Cache類調用函數的方法基本鬥是這樣, init()擷取 到handler,然後操作handler對象,也就是我們真正的 操作對象,這裡就是 phpredis類啦,

當然我們是沒辦法直接操作 phpredis類的, 只能使用Cache類 的寥寥幾種方法,所以有些人不滿意,因為隊列,集和,雜湊都認為沒辦法使用了,我也在網上看到有些同學 重寫TP5的 redis類

其實大可不必, Cache類還是暴露了一個介面給我們的.

我們可以這樣

        $res  = Cache::init();                $redis = $res->handler();                $redis->lpush('test',111);                $redis->rpush('test',111);                $redis->lpop('test');

獲得了 handler 也就是獲得了 phpredis,這樣就可以隨便使用 phpredis原生的方法啦,而且還是單例模式哦, 沒有建立對象額外的消耗

本文就到這裡結束啦, 如果要知道更多Cache類的使用方法,可以按上文的方式直接看原始碼,或者再去查閱官方文檔.

雖然沒有講解如何使用,但是分析了 Cache的實現原理有助於提高我們的編程抽象水平, 上文分析源碼的方式也同樣可以用來分析其他的核心類庫.

相關閱讀:

ThinkPHP5商城項目實戰視頻教程課件源碼分享

thinkphp5入門該瞭解的知識

thinkphp5.0學習筆記之資料庫的操作

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.