Smarty默认是使用基于文件的缓存机制,作为可选的方案,你可以自定义一套缓存机制的实现,来进行缓存文件的读写和删除。
Note
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();
}
}
?>
