自定义缓存实现

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实现自定义缓存机制

  1. <?php
  2.  
  3. require_once 'libs/Smarty.class.php';
  4. $smarty = new Smarty();
  5. $smarty->caching_type = 'mysql';
  6.  
  7. /**
  8. * MySQL 缓存
  9. *
  10. * 通过自定义缓存的接口API,让MySQL来作为Smarty的输出缓存存储器。
  11. *
  12. * 表定义:
  13. * <pre>CREATE TABLE IF NOT EXISTS `output_cache` (
  14. * `id` CHAR(40) NOT NULL COMMENT 'sha1 hash',
  15. * `name` VARCHAR(250) NOT NULL,
  16. * `cache_id` VARCHAR(250) NULL DEFAULT NULL,
  17. * `compile_id` VARCHAR(250) NULL DEFAULT NULL,
  18. * `modified` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  19. * `content` LONGTEXT NOT NULL,
  20. * PRIMARY KEY (`id`),
  21. * INDEX(`name`),
  22. * INDEX(`cache_id`),
  23. * INDEX(`compile_id`),
  24. * INDEX(`modified`)
  25. * ) ENGINE = InnoDB;</pre>
  26. *
  27. * @package CacheResource-examples
  28. * @author Rodney Rehm
  29. */
  30. class Smarty_CacheResource_Mysql extends Smarty_CacheResource_Custom {
  31. // PDO 对象
  32. protected $db;
  33. protected $fetch;
  34. protected $fetchTimestamp;
  35. protected $save;
  36.  
  37. public function __construct() {
  38. try {
  39. $this->db = new PDO("mysql:dbname=test;host=127.0.0.1", "smarty", "smarty");
  40. } catch (PDOException $e) {
  41. throw new SmartyException('Mysql 源无法链接: ' . $e->getMessage());
  42. }
  43. $this->fetch = $this->db->prepare('SELECT modified, content FROM output_cache WHERE id = :id');
  44. $this->fetchTimestamp = $this->db->prepare('SELECT modified FROM output_cache WHERE id = :id');
  45. $this->save = $this->db->prepare('REPLACE INTO output_cache (id, name, cache_id, compile_id, content)
  46. VALUES (:id, :name, :cache_id, :compile_id, :content)');
  47. }
  48.  
  49. /**
  50. * 从数据表中获取缓存的内容及修改时间
  51. *
  52. * @param string $id 缓存内容的唯一识别ID
  53. * @param string $name 模板名称
  54. * @param string $cache_id 缓存ID
  55. * @param string $compile_id 编译ID
  56. * @param string $content (引用的)缓存内容
  57. * @param integer $mtime 缓存修改的时间戳 (epoch)
  58. * @return void
  59. */
  60. protected function fetch($id, $name, $cache_id, $compile_id, &$content, &$mtime)
  61. {
  62. $this->fetch->execute(array('id' => $id));
  63. $row = $this->fetch->fetch();
  64. $this->fetch->closeCursor();
  65. if ($row) {
  66. $content = $row['content'];
  67. $mtime = strtotime($row['modified']);
  68. } else {
  69. $content = null;
  70. $mtime = null;
  71. }
  72. }
  73.  
  74. /**
  75. * 从数据表中获取缓存的修改时间
  76. *
  77. * @note 这是个可选的实现接口。在你确定仅获取修改时间会比获取整个内容要更快的时候,使用此接口。
  78. * @param string $id 缓存内容的唯一识别ID
  79. * @param string $name 模板名称
  80. * @param string $cache_id 缓存ID
  81. * @param string $compile_id 编译ID
  82. * @return integer|boolean 返回模板修改时间,如果找不到缓存则返回false
  83. */
  84. protected function fetchTimestamp($id, $name, $cache_id, $compile_id)
  85. {
  86. $this->fetchTimestamp->execute(array('id' => $id));
  87. $mtime = strtotime($this->fetchTimestamp->fetchColumn());
  88. $this->fetchTimestamp->closeCursor();
  89. return $mtime;
  90. }
  91.  
  92. /**
  93. * 保存缓存内容到数据表
  94. *
  95. * @param string $id 缓存内容的唯一识别ID
  96. * @param string $name 模板名称
  97. * @param string $cache_id 缓存ID
  98. * @param string $compile_id 编译ID
  99. * @param integer|null $exp_time 缓存过期时间,或null
  100. * @param string $content 需要缓存的内容
  101. * @return boolean 成功true,失败false
  102. */
  103. protected function save($id, $name, $cache_id, $compile_id, $exp_time, $content)
  104. {
  105. $this->save->execute(array(
  106. 'id' => $id,
  107. 'name' => $name,
  108. 'cache_id' => $cache_id,
  109. 'compile_id' => $compile_id,
  110. 'content' => $content,
  111. ));
  112. return !!$this->save->rowCount();
  113. }
  114.  
  115. /**
  116. * 从数据表中删除缓存
  117. *
  118. * @param string $name 模板名称
  119. * @param string $cache_id 缓存ID
  120. * @param string $compile_id 编译ID
  121. * @param integer|null $exp_time 缓存过期时间,或null
  122. * @return integer 返回被删除的缓存数量
  123. */
  124. protected function delete($name, $cache_id, $compile_id, $exp_time)
  125. {
  126. // 删除整个缓存
  127. if ($name === null && $cache_id === null && $compile_id === null && $exp_time === null) {
  128. // 返回删除缓存记录的数量,需要再进行一次查询来计算。
  129. $query = $this->db->query('TRUNCATE TABLE output_cache');
  130. return -1;
  131. }
  132. // 组成查找条件
  133. $where = array();
  134. // 匹配名称
  135. if ($name !== null) {
  136. $where[] = 'name = ' . $this->db->quote($name);
  137. }
  138. // 匹配编译ID
  139. if ($compile_id !== null) {
  140. $where[] = 'compile_id = ' . $this->db->quote($compile_id);
  141. }
  142. // 匹配过期时间范围
  143. if ($exp_time !== null) {
  144. $where[] = 'modified < DATE_SUB(NOW(), INTERVAL ' . intval($exp_time) . ' SECOND)';
  145. }
  146. // 匹配缓存ID和缓存组的子ID
  147. if ($cache_id !== null) {
  148. $where[] = '(cache_id = '. $this->db->quote($cache_id)
  149. . ' OR cache_id LIKE '. $this->db->quote($cache_id .'|%') .')';
  150. }
  151. // 执行删除
  152. $query = $this->db->query('DELETE FROM output_cache WHERE ' . join(' AND ', $where));
  153. return $query->rowCount();
  154. }
  155. }
  156. ?>
  157.  


Example 15.16. 通过Memcache实现自定义缓存机制

  1. <?php
  2.  
  3. require_once 'libs/Smarty.class.php';
  4. $smarty = new Smarty();
  5. $smarty->caching_type = 'memcache';
  6.  
  7. /**
  8. * Memcache 缓存
  9. *
  10. * 通过K-V存储的API来把memcache作为Smarty的输出缓存器。
  11. *
  12. * 注意memcache要求key的长度只能是256个字符以内,
  13. * 所以程序中,key都进行sha1哈希计算后才使用。
  14. *
  15. * @package CacheResource-examples
  16. * @author Rodney Rehm
  17. */
  18. class Smarty_CacheResource_Memcache extends Smarty_CacheResource_KeyValueStore {
  19. /**
  20. * memcache 对象
  21. * @var Memcache
  22. */
  23. protected $memcache = null;
  24.  
  25. public function __construct()
  26. {
  27. $this->memcache = new Memcache();
  28. $this->memcache->addServer( '127.0.0.1', 11211 );
  29. }
  30.  
  31. /**
  32. * 从memcache中获取一系列key的值。
  33. *
  34. * @param array $keys 多个key
  35. * @return array 按key的顺序返回的对应值
  36. * @return boolean 成功返回true,失败返回false
  37. */
  38. protected function read(array $keys)
  39. {
  40. $_keys = $lookup = array();
  41. foreach ($keys as $k) {
  42. $_k = sha1($k);
  43. $_keys[] = $_k;
  44. $lookup[$_k] = $k;
  45. }
  46. $_res = array();
  47. $res = $this->memcache->get($_keys);
  48. foreach ($res as $k => $v) {
  49. $_res[$lookup[$k]] = $v;
  50. }
  51. return $_res;
  52. }
  53.  
  54. /**
  55. * 将一系列的key对应的值存储到memcache中。
  56. *
  57. * @param array $keys 多个kv对应的数据值
  58. * @param int $expire 过期时间
  59. * @return boolean 成功返回true,失败返回false
  60. */
  61. protected function write(array $keys, $expire=null)
  62. {
  63. foreach ($keys as $k => $v) {
  64. $k = sha1($k);
  65. $this->memcache->set($k, $v, 0, $expire);
  66. }
  67. return true;
  68. }
  69.  
  70. /**
  71. * 从memcache中删除
  72. *
  73. * @param array $keys 待删除的多个key
  74. * @return boolean 成功返回true,失败返回false
  75. */
  76. protected function delete(array $keys)
  77. {
  78. foreach ($keys as $k) {
  79. $k = sha1($k);
  80. $this->memcache->delete($k);
  81. }
  82. return true;
  83. }
  84.  
  85. /**
  86. * 清空全部的值
  87. *
  88. * @return boolean 成功返回true,失败返回false
  89. */
  90. protected function purge()
  91. {
  92. return $this->memcache->flush();
  93. }
  94. }
  95. ?>
  96.  

原文: https://www.smarty.net/docs/zh_CN/caching.custom.tpl