Smarty默认是使用基于文件的缓存机制,作为可选的方案,你可以自定义一套缓存机制的实现,来进行缓存文件的读写和删除。
Smarty2使用$cache_handler_func
的回调函数来实现此功能。
而Smarty3使用了Smarty_CacheResource
模块来实现。
自定义缓存实现可以实现类似下面的目的: 用更快的存储引擎来替代较慢的文件系统, 使缓存可以分布到多台服务器上。
Smarty可以通过API Smarty_CacheResource_Custom
或者 Smarty_CacheResource_KeyValueStore
来实现缓存机制。
Smarty_CacheResource_Custom
是比较简单的API,直接通过覆盖读、写、删除等操作来实现缓存机制。
该API可以使用于任何你觉得适合的方式,或存储到任何你觉得适合的地方。
Smarty_CacheResource_KeyValueStore
的API可让你使用K-V存储模式(比如APC,Memcache等)来实现缓存机制。
更进一步,就算是多层的缓存组如"a|b|c",该API也让你可以通过删除缓存组"a"来将整个嵌套的缓存组删除,
即使K-V存储机制本身无法实现这种层次结构的存储。
自定义缓存可以放到$plugins_dir
目录下并命名为cacheresource.foobarxyz.php
,
或者在运行时通过registerCacheResource()
来进行注册。
上面两种方式都必须设置$caching_type
来启动你的自定义缓存机制。
Example 15.15. 通过MySQL实现自定义缓存机制
<?php require_once 'libs/Smarty.class.php'; $smarty = new Smarty(); $smarty->caching_type = 'mysql'; /** * MySQL 缓存 * * 通过自定义缓存的接口API,让MySQL来作为Smarty的输出缓存存储器。 * * 表定义: * <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 对象 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 源无法链接: ' . $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)'); } /** * 从数据表中获取缓存的内容及修改时间 * * @param string $id 缓存内容的唯一识别ID * @param string $name 模板名称 * @param string $cache_id 缓存ID * @param string $compile_id 编译ID * @param string $content (引用的)缓存内容 * @param integer $mtime 缓存修改的时间戳 (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; } } /** * 从数据表中获取缓存的修改时间 * * @note 这是个可选的实现接口。在你确定仅获取修改时间会比获取整个内容要更快的时候,使用此接口。 * @param string $id 缓存内容的唯一识别ID * @param string $name 模板名称 * @param string $cache_id 缓存ID * @param string $compile_id 编译ID * @return integer|boolean 返回模板修改时间,如果找不到缓存则返回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; } /** * 保存缓存内容到数据表 * * @param string $id 缓存内容的唯一识别ID * @param string $name 模板名称 * @param string $cache_id 缓存ID * @param string $compile_id 编译ID * @param integer|null $exp_time 缓存过期时间,或null * @param string $content 需要缓存的内容 * @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(); } /** * 从数据表中删除缓存 * * @param string $name 模板名称 * @param string $cache_id 缓存ID * @param string $compile_id 编译ID * @param integer|null $exp_time 缓存过期时间,或null * @return integer 返回被删除的缓存数量 */ protected function delete($name, $cache_id, $compile_id, $exp_time) { // 删除整个缓存 if ($name === null && $cache_id === null && $compile_id === null && $exp_time === null) { // 返回删除缓存记录的数量,需要再进行一次查询来计算。 $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); } // 匹配过期时间范围 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 .'|%') .')'; } // 执行删除 $query = $this->db->query('DELETE FROM output_cache WHERE ' . join(' AND ', $where)); return $query->rowCount(); } } ?>
Example 15.16. 通过Memcache实现自定义缓存机制
<?php require_once 'libs/Smarty.class.php'; $smarty = new Smarty(); $smarty->caching_type = 'memcache'; /** * Memcache 缓存 * * 通过K-V存储的API来把memcache作为Smarty的输出缓存器。 * * 注意memcache要求key的长度只能是256个字符以内, * 所以程序中,key都进行sha1哈希计算后才使用。 * * @package CacheResource-examples * @author Rodney Rehm */ class Smarty_CacheResource_Memcache extends Smarty_CacheResource_KeyValueStore { /** * memcache 对象 * @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 多个key * @return array 按key的顺序返回的对应值 * @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对应的值存储到memcache中。 * * @param array $keys 多个kv对应的数据值 * @param int $expire 过期时间 * @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 待删除的多个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(); } } ?>