Smarty是一个PHP的模板引擎。
Smarty的核心实际上是一个编译器。这个编译器需要解决两个问题:
下面的分析以Smarty 3.0.2版本为基础。
Smarty模板的语法解析器(parser)对应的Php文件为smarty_internal_templateparser.php
。
在解析到Smarty标签的时候,会调用相应的class以进行内部状态设置和转换。这些class放在特定命名规则的PHP文件中。
Smarty模板中的标签对应的php文件名以smarty_internal_compile_
开头。比如:
对于Smarty自带的标签,以nocache
标签为例,相对应的php文件为
smarty_internal_compile_nocache.php
: Smarty自带的nocache
标签smarty_internal_compile_private_registered_block.php
: 用户registerPlugin
的block类型标签smarty_internal_compile_private_block_plugin.php
: 用户扩展的block类型标签以Smarty自带的nocache
标签为例,文件smarty_internal_compile_nocache.php
的内容可以概要如下,它定义了两个class以分别对应开始标签和结束标签。
<?php // 对应开始标签 class Smarty_Internal_Compile_Nocache extends Smarty_Internal_CompileBase { public function compile($args, $compiler){ $this->compiler = $compiler; $this->compiler->nocache = true; // 禁止缓存 $this->compiler->has_code = false; // 标签内容不包含代码 return true; } } // 对应结束标签 class Smarty_Internal_Compile_Nocacheclose extends Smarty_Internal_CompileBase { public function compile($args, $compiler){ $this->compiler = $compiler; $this->compiler->nocache = false; // 恢复为允许缓存 $this->compiler->has_code = false; // 标签内容不包含代码 return true; } } ?>
如果是用户扩展的标签,虽然实现方法有所不同,但主要目的也是分别针对开始和结束标签作相应的状态设置和代码生成。
Smarty模板需要缓存的对象主要有两种:变量本身和由文本变量等组成的段落区块。
上面的nocache
标签的实现代码中提到了两个变量 $compiler->nocache
和$compiler->has_code
。
nocache变量用于控制模板解析器的状态以决定是否对模板中的变量进行缓存;has_code则最终决定是否需要对生成的PHP代码作"nocache"处理。nocache是标,has_code是本。nocache作用在模板变量上以决定模板变量的has_code值。
很显然,只有has_code值为false的部分才可以生成缓存,否则则需要动态生成。
对于不能缓存而需要动态生成的部分,Smarty的实现机制可以简单表述如下:
<? echo $value_cache; ?> <? echo '/*%%SmartyNocache:hash_string%%*/', '<?php echo $value_nocache;?>', '/*/%%SmartyNocache:hash_string%%*/'; ?>
上面的代码是Compiled Template中PHP代码的样子。第一个echo是需要缓存的变量对应的PHP代码,第二个echo则是不需要缓存的变量对应的PHP代码。
如果页面不需要缓存的情况下,可以通过修改"SmartyNocache"字样所标识部分的代码为直接执行而不是echo,就可以获得最终输出。
如果页面需要缓存,则把Compiled Template的执行输出保存为缓存文件,这时那些不需要缓存的部分实际上变成了PHP代码,这时再次执行缓存文件的输出结果就是最终输出。
上面提到Smarty内部是通过变量$nocache
来控制是否需要缓存的。如果Smarty模板中的标签包含nocache
属性,或者用户通过registerPlugin扩展的plugin指定了nocache属性,Smarty内部都会通过变量$tag_nocache
进行记录。并在需要时按照下面的计算更新$nocache
的值:
$nocache = $nocache | $tag_nocache;
这种方式表明,只要一个block被标识为nocache
,那它内部所有的内容都会被认为是不能缓存的。这在有些情况下会带来一些不方便。
TODO