What is Smarty?
Why use it?
Use Cases and Work Flow
Syntax Comparison
Template Inheritance
Best Practices
Crash Course
You may use the Smarty logo according to the trademark notice.
For sponsorship, advertising, news or other inquiries, contact us at:
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(); } } ?>