原创日志

奇妙的smarty快函数smarty_block_name,以插件扩展Smarty之二,解密篇

[ 2020-05-14 19:51:45 | 作者: admin ]
字号: | |
p.s.嗯。。看到这个smarty块函数插件的编译解释逻辑实在太绕了,也亏的作者能想出来。如果用原生php,几行代码的事,效率差距太大太大。

上次写过一篇关于smarty_block_name的疑惑,这次来说下它的实现原理,以便于理解这玩意怎么赋值和生效的

模板片段如下,定义一个自定义块 block
<block parent_id="6" ><li>{$item.title}</li></block>

然后在插件plugin中加上 smarty_block_block ,使用$GLOBALS[$index]定义一个全局变量来存储数组$items,入栈出栈$item
function smarty_block_block($params,   $content,   $template, &$repeat){
...
}

运行后,我们看看smarty cache目录产生的编译后文件,做了简化

<?php
              $_smarty_tpl->smarty->_tag_stack[] = array('block', array('parent_id'=>8)); //入栈,把新block标签放入 _tag_stack[]
              $_block_repeat=true; //重复标志初始值为true
              //第一次调用smarty_block_block(),模板内容null,这次调用实际上可以全局变量赋值$items,同时赋值$item=$items[0]
              //$_smarty_tpl->tpl_vars[item]此时已经赋值了第一行,也就是 $items[0],进入循环后在中间文件直接使用,而不是在smarty_block_block()
            echo smarty_block_block(array(''parent_id'=>8), null, $_smarty_tpl, $_block_repeat);
            //循环显示数据,直到把引用变量$_block_repeat为 false
            //再次强调,此时只要$items有数据,则$_smarty_tpl->tpl_vars[item]就是第一行的数据,已被赋值了
            while ($_block_repeat) {
                    //ob_start();把要显示到浏览器的内容放到内存缓存起来,注意这个内容是php执行后的静态文本
                    ob_start();
                    //下面这行$_smarty_tpl->tpl_vars是 assign赋值的产物,所以如果不想assign,直接每次while行的时候 $_smarty_tpl->tpl_vars[item] 其实也一样
                    //显然本次循环的$item数据是上次调用smarty_block_block()时候赋值给$_smarty_tpl->tpl_vars[item]的,所以这才是这个循环最难理解的地方

?>
                    <li><?php echo $_smarty_tpl->tpl_vars['item']->value['title'];?></li>
<?php
                   //下一行是把前面本次循环生成的缓存文本赋值给 $_block_content 作为静态内容交给smarty_block_block,显然$_block_content不会包含任何smarty标签
                   $_block_content = ob_get_clean();
                   $_block_repeat=false; //每次循环后就默认把$_block_repeat变false,如果smarty_block_block主动设置会true,则继续循环
                   //每个循环结尾调用smarty_block_block,判断是否还有行,有就赋值给$_smarty_tpl->tpl_vars[item],为下次循环做准备
                   //$_block_content参数是本身是静态无标签的,传递给smarty_block_block毫无意义,其实直接显示也可以啊
                    echo smarty_block_block(array(''parent_id'=>8), $_block_content , $_smarty_tpl, $_block_repeat);
          }
          array_pop($_smarty_tpl->smarty->_tag_stack); //出栈,把最后放入的block标签删除
?>


后续,关于块函数中存在调用块函数的嵌套情况说明
模板片段如下,定义一个嵌套自定义块 block,如果都使用$item就会冲突,这个时候需要做2个事情来避免:
1、模板页面自定义下item名字
2、smarty_block_name()中获取$params[item],赋值的时候赋值给 $smarty->assign($params[item],$item) 就行了
<block parent_id="6" >
<li>
       {$item.title}
       <block parent_id="{$item.id}" ><span>{$item.title}</span></block>
</li>
</block>
可以修改为
<block parent_id="6" item="item">
<li>
       {$item.title}
       <block parent_id="{$item.id}" item="itemchild"><span>{$itemchild.title}</span></block>
</li>
</block>
[最后修改由 admin, 于 2020-05-15 10:29:49]
评论Feed 评论Feed: http://blog.xg98.com/feed.asp?q=comment&id=2669

这篇日志没有评论。

此日志不可发表评论。