问题
smarty3的一个很重要,也是很方便的特性是模板继承。今天碰到了一个模板继承相关的题,记录一下。
原码有点多,所以将问题代码抽象如下:
tpl.parent.htm:
{block name="body"} parent body {/block} {include file="tpl.parentFooter.htm"}
{block name="footer"} parent footer {/block}
{extends file="admin/tpl.parent.htm"} {block name="body"} child1 body {/block} {block name="footer"} child1 footer {/block}
{extends file="admin/tpl.parent.htm"} {block name="body"} child2 body {/block} {block name="footer"} child2 footer {/block}
但实际的结果令人沮丧,我们看到的是:
child2 body child1 footer
清理c_template目录中的模板编译文件。调换一下渲染顺序(先tpl.child2.htm,再tpl.child1.htm),得到的结果分别是:
child2 body child2 footer
child1 body child2 footer
what's wrong! 是伟大的继承机制有bug,还是我们做错了什么?
解决
几经实验,发现将tpl.parentFooter.htm的代码直接写入tpl.parent.htm,而不是用include的方式引入,渲染模板的结果和我们的预期是一致的。当然,如果情况所需,必须要使用include也是有办法的,那就是使用inline参数。
将tpl.parent.htm的最后一行改为:
{include file="tpl.parentFooter.htm" inline}问题也可得以解决。
试着分析下原因
对于编译好的模板文件,smarty不会重新处理其block部分,而只是对模板中的assign的变量做替换。除非有某种条件可以让模板文件被重新编译,比如模板自身有了修改或者编译好的模板文件被删除。
对应我们的例子,由于tpl.parentFooter.htm被两个模板共用,自然哪个模板先被渲染,其block部分就先被写进tpl.parentFooter.htm的编译文件。二次渲染时,tpl.parentFooter.htm的编译文件内容被未改变,自然得到的只能是之前的内容。
再看代码,在先渲染tpl.child1.htm时,tpl.parentFooter.htm对应的编译文件
4f8eb313212228edb2051b2212bfffc596075d43.file.tpl.parentFooter.htm.php
最后几行为block相应的代码
<?php if ($_valid && !is_callable('content_5321c3377c1fc9_56610175')) {function content_5321c3377c1fc9_56610175($_smarty_tpl) {?> child1 footer <?php }} ?>
在渲染tpl.child2.htm时,由于tpl.parentFooter.htm对应的编译文件已生成,不会重新编译,自然就只能得到child1 footer的内容了。