问题 smarty3的一个很重要,也是很方便的特性是模板继承。今天碰到了一个模板继承相关的题,记录一下。 原码有点多,所以将问题代码抽象如下: tpl.parent.htm:
{block name="body"}
parent body
{/block}
{include file="tpl.parentFooter.htm"}
tpl.parentFooter.htm:
{block name="footer"}
parent footer
{/block}
tpl.child1.htm
{extends file="admin/tpl.parent.htm"}
{block name="body"}
child1 body
{/block}
{block name="footer"}
child1 footer
{/block}
tpl.child2.htm
{extends file="admin/tpl.parent.htm"}
{block name="body"}
child2 body
{/block}
{block name="footer"}
child2 footer
{/block}
渲染tpl.child1.htm,我们得到页面 child1 body child1 footer 接着渲染tpl.child2.htm。我们预期的结果是: child2 body child2 footer
但实际的结果令人沮丧,我们看到的是: 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 }} ?>
我们将其含意理解为,如果使用block,相应内容为child1 footer。
在渲染tpl.child2.htm时,由于tpl.parentFooter.htm对应的编译文件已生成,不会重新编译,自然就只能得到child1 footer的内容了。