Smarty自定義緩存實(shí)現(xiàn)

2018-12-09 11:41 更新

自定義緩存實(shí)現(xiàn)

Smarty默認(rèn)是使用基于文件的緩存機(jī)制,作為可選的方案,你可以自定義一套緩存機(jī)制的實(shí)現(xiàn),來(lái)進(jìn)行緩存文件的讀寫(xiě)和刪除。

溫馨提示

Smarty2使用$cache_handler_func的回調(diào)函數(shù)來(lái)實(shí)現(xiàn)此功能。 而Smarty3使用了Smarty_CacheResource模塊來(lái)實(shí)現(xiàn)。

自定義緩存實(shí)現(xiàn)可以實(shí)現(xiàn)類似下面的目的: 用更快的存儲(chǔ)引擎來(lái)替代較慢的文件系統(tǒng), 使緩存可以分布到多臺(tái)服務(wù)器上。

Smarty可以通過(guò)API Smarty_CacheResource_Custom 或者Smarty_CacheResource_KeyValueStore 來(lái)實(shí)現(xiàn)緩存機(jī)制。Smarty_CacheResource_Custom是比較簡(jiǎn)單的API,直接通過(guò)覆蓋讀、寫(xiě)、刪除等操作來(lái)實(shí)現(xiàn)緩存機(jī)制。 該API可以使用于任何你覺(jué)得適合的方式,或存儲(chǔ)到任何你覺(jué)得適合的地方。Smarty_CacheResource_KeyValueStore的API可讓你使用K-V存儲(chǔ)模式(比如APC,Memcache等)來(lái)實(shí)現(xiàn)緩存機(jī)制。 更進(jìn)一步,就算是多層的緩存組如"a|b|c",該API也讓你可以通過(guò)刪除緩存組"a"來(lái)將整個(gè)嵌套的緩存組刪除, 即使K-V存儲(chǔ)機(jī)制本身無(wú)法實(shí)現(xiàn)這種層次結(jié)構(gòu)的存儲(chǔ)。

自定義緩存可以放到$plugins_dir目錄下并命名為cacheresource.foobarxyz.php, 或者在運(yùn)行時(shí)通過(guò)registerCacheResource() 來(lái)進(jìn)行注冊(cè)。 上面兩種方式都必須設(shè)置$caching_type 來(lái)啟動(dòng)你的自定義緩存機(jī)制。

Example 15.15. 通過(guò)MySQL實(shí)現(xiàn)自定義緩存機(jī)制

<?php

require_once 'libs/Smarty.class.php';
$smarty = new Smarty();
$smarty->caching_type = 'mysql';

/**
 * MySQL 緩存
 *
 * 通過(guò)自定義緩存的接口API,讓MySQL來(lái)作為Smarty的輸出緩存存儲(chǔ)器。
 *
 * 表定義:
 * <pre>CREATE TABLE IF NOT EXISTS `output_cache` (
 *   `id` CHAR(40) NOT NULL COMMENT 'sha1 hash',
 *   `name` VARCHAR(250) NOT NULL,
 *   `cache_id` VARCHAR(250) NULL DEFAULT NULL,
 *   `compile_id` VARCHAR(250) NULL DEFAULT NULL,
 *   `modified` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
 *   `content` LONGTEXT NOT NULL,
 *   PRIMARY KEY (`id`),
 *   INDEX(`name`),
 *   INDEX(`cache_id`),
 *   INDEX(`compile_id`),
 *   INDEX(`modified`)
 * ) ENGINE = InnoDB;</pre>
 *
 * @package CacheResource-examples
 * @author Rodney Rehm
 */
class Smarty_CacheResource_Mysql extends Smarty_CacheResource_Custom {
    // PDO 對(duì)象
    protected $db;
    protected $fetch;
    protected $fetchTimestamp;
    protected $save;
    
    public function __construct() {
        try {
            $this->db = new PDO("mysql:dbname=test;host=127.0.0.1", "smarty", "smarty");
        } catch (PDOException $e) {
            throw new SmartyException('Mysql 源無(wú)法鏈接: ' . $e->getMessage());
        }
        $this->fetch = $this->db->prepare('SELECT modified, content FROM output_cache WHERE id = :id');
        $this->fetchTimestamp = $this->db->prepare('SELECT modified FROM output_cache WHERE id = :id');
        $this->save = $this->db->prepare('REPLACE INTO output_cache (id, name, cache_id, compile_id, content)
            VALUES  (:id, :name, :cache_id, :compile_id, :content)');
    }

    /**
	 * 從數(shù)據(jù)表中獲取緩存的內(nèi)容及修改時(shí)間
     *
     * @param string $id 緩存內(nèi)容的唯一識(shí)別ID
     * @param string $name 模板名稱
     * @param string $cache_id 緩存ID
     * @param string $compile_id 編譯ID
     * @param string $content (引用的)緩存內(nèi)容
     * @param integer $mtime 緩存修改的時(shí)間戳 (epoch)
     * @return void
     */
    protected function fetch($id, $name, $cache_id, $compile_id, &$content, &$mtime)
    {
        $this->fetch->execute(array('id' => $id));
        $row = $this->fetch->fetch();
        $this->fetch->closeCursor();        
        if ($row) {
            $content = $row['content'];
            $mtime = strtotime($row['modified']);
        } else {
            $content = null;
            $mtime = null;
        }
    }
    
    /**
	 * 從數(shù)據(jù)表中獲取緩存的修改時(shí)間
     *
     * @note 這是個(gè)可選的實(shí)現(xiàn)接口。在你確定僅獲取修改時(shí)間會(huì)比獲取整個(gè)內(nèi)容要更快的時(shí)候,使用此接口。
     * @param string $id 緩存內(nèi)容的唯一識(shí)別ID
     * @param string $name 模板名稱
     * @param string $cache_id 緩存ID
     * @param string $compile_id 編譯ID
     * @return integer|boolean 返回模板修改時(shí)間,如果找不到緩存則返回false
     */
    protected function fetchTimestamp($id, $name, $cache_id, $compile_id)
    {
        $this->fetchTimestamp->execute(array('id' => $id));
        $mtime = strtotime($this->fetchTimestamp->fetchColumn());
        $this->fetchTimestamp->closeCursor();
        return $mtime;
    }
    
    /**
     * 保存緩存內(nèi)容到數(shù)據(jù)表
     *
     * @param string $id 緩存內(nèi)容的唯一識(shí)別ID
     * @param string $name 模板名稱
     * @param string $cache_id 緩存ID
     * @param string $compile_id 編譯ID
     * @param integer|null $exp_time 緩存過(guò)期時(shí)間,或null
     * @param string $content 需要緩存的內(nèi)容
     * @return boolean 成功true,失敗false
     */
    protected function save($id, $name, $cache_id, $compile_id, $exp_time, $content)
    {
        $this->save->execute(array(
            'id' => $id,
            'name' => $name,
            'cache_id' => $cache_id,
            'compile_id' => $compile_id,
            'content' => $content,
        ));
        return !!$this->save->rowCount();
    }
    
    /**
     * 從數(shù)據(jù)表中刪除緩存
     *
     * @param string $name 模板名稱
     * @param string $cache_id 緩存ID
     * @param string $compile_id 編譯ID
     * @param integer|null $exp_time 緩存過(guò)期時(shí)間,或null
     * @return integer 返回被刪除的緩存數(shù)量
     */
    protected function delete($name, $cache_id, $compile_id, $exp_time)
    {
        // 刪除整個(gè)緩存
        if ($name === null && $cache_id === null && $compile_id === null && $exp_time === null) {
			// 返回刪除緩存記錄的數(shù)量,需要再進(jìn)行一次查詢來(lái)計(jì)算。
            $query = $this->db->query('TRUNCATE TABLE output_cache');
            return -1;
        }
        // 組成查找條件
        $where = array();
        // 匹配名稱
        if ($name !== null) {
            $where[] = 'name = ' . $this->db->quote($name);
        }
        // 匹配編譯ID
        if ($compile_id !== null) {
            $where[] = 'compile_id = ' . $this->db->quote($compile_id);
        }
        // 匹配過(guò)期時(shí)間范圍
        if ($exp_time !== null) {
            $where[] = 'modified < DATE_SUB(NOW(), INTERVAL ' . intval($exp_time) . ' SECOND)';
        }
        // 匹配緩存ID和緩存組的子ID
        if ($cache_id !== null) {
            $where[] = '(cache_id = '. $this->db->quote($cache_id)
                . ' OR cache_id LIKE '. $this->db->quote($cache_id .'|%') .')';
        }
        // 執(zhí)行刪除
        $query = $this->db->query('DELETE FROM output_cache WHERE ' . join(' AND ', $where));
        return $query->rowCount();
    }
}
?>

Example 15.16. 通過(guò)Memcache實(shí)現(xiàn)自定義緩存機(jī)制

<?php

require_once 'libs/Smarty.class.php';
$smarty = new Smarty();
$smarty->caching_type = 'memcache';

/**
 * Memcache 緩存
 *
 * 通過(guò)K-V存儲(chǔ)的API來(lái)把memcache作為Smarty的輸出緩存器。
 *
 * 注意memcache要求key的長(zhǎng)度只能是256個(gè)字符以內(nèi),
 * 所以程序中,key都進(jìn)行sha1哈希計(jì)算后才使用。
 *
 * @package CacheResource-examples
 * @author Rodney Rehm
 */
class Smarty_CacheResource_Memcache extends Smarty_CacheResource_KeyValueStore {
    /**
     * memcache 對(duì)象
     * @var Memcache
     */
    protected $memcache = null;
    
    public function __construct()
    {
        $this->memcache = new Memcache();
        $this->memcache->addServer( '127.0.0.1', 11211 );
    }
    
    /**
	 * 從memcache中獲取一系列key的值。
     *
     * @param array $keys 多個(gè)key
     * @return array 按key的順序返回的對(duì)應(yīng)值
     * @return boolean 成功返回true,失敗返回false
     */
    protected function read(array $keys)
    {
        $_keys = $lookup = array();
        foreach ($keys as $k) {
            $_k = sha1($k);
            $_keys[] = $_k;
            $lookup[$_k] = $k;
        }
        $_res = array();
        $res = $this->memcache->get($_keys);
        foreach ($res as $k => $v) {
            $_res[$lookup[$k]] = $v;
        }
        return $_res;
    }
    
    /**
	 * 將一系列的key對(duì)應(yīng)的值存儲(chǔ)到memcache中。
     *
     * @param array $keys 多個(gè)kv對(duì)應(yīng)的數(shù)據(jù)值
     * @param int $expire 過(guò)期時(shí)間
     * @return boolean 成功返回true,失敗返回false
     */
    protected function write(array $keys, $expire=null)
    {
        foreach ($keys as $k => $v) {
            $k = sha1($k);
            $this->memcache->set($k, $v, 0, $expire);
        }
        return true;
    }

    /**
	 * 從memcache中刪除
     *
     * @param array $keys 待刪除的多個(gè)key
     * @return boolean 成功返回true,失敗返回false
     */
    protected function delete(array $keys)
    {
        foreach ($keys as $k) {
            $k = sha1($k);
            $this->memcache->delete($k);
        }
        return true;
    }

    /**
     * 清空全部的值
     *
     * @return boolean 成功返回true,失敗返回false
     */
    protected function purge()
    {
        return $this->memcache->flush();
    }
}
?>
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)