解决ThinkPHP模板常量解析失败

ThinkPHP在设计时没有考虑过把__XXX__这种模板常量用在一些PHP操作上,比如模板继承、Include标签统统不能用模板常量,比如下面这样ThinkPHP是不解析的,直接过滤掉。

    <include file="__PUBLIC__/nav.html" />

其原因有2

1.URL路径PHP是不认的,PHP引用文件需要文件路径

比如引用js文件你可以这样

127.0.0.1/nut_shop/Public/jQuery.js

而引用PHP文件则需要

./Public/nav.html

路径种类是不同的,就算ThinkPHP解析,最后的执行结果也是错的,更何况ThinkPHP不解析。

所以,如果你非要用,可以定义参考手册中“模板替换”章节定义一个模板常量

TMPL_PARSE_STRING' =>array(
    __FILE_PUBLIC__' => './Public',
)

不过尽管你定义了,还是会被无情的过滤掉,参考下面。

2.ThinkPHP的渲染流程是,过滤在解析常量之前。

简单说下ThinkPHP的模板渲染流程,参考文件:

.\ThinkPHP\Library\Think\Template.class.php

流程如下:

  1. 读入模板文件
  2. 渲染模板继承&布局
  3. 渲染Include标签
  4. 渲染模板常量

所以我们需要修改代码让流程变成这样

  1. 读入模板文件
  2. 渲染模板常量
  3. 渲染模板继承&布局
  4. 渲染模板常量
  5. 渲染Include标签
  6. 渲染模板常量

这样就好了。
改动代码如下,参考原ThinkPHP代码,带PeA标示的为新增的代码:

    protected function compiler($tmplContent) {
        //PeA:模版编译过滤标签,替换各种__XXX__常量
        //PeA:这里在开始解析一遍,解析完布局和继承解析一遍,末尾再解析一遍,可以确保include等特殊标签页支持__XXX__常量
        Hook::listen('template_filter',$tmplContent);
        //模板解析
        $tmplContent =  $this->parse($tmplContent);
        // 还原被替换的Literal标签
        $tmplContent =  preg_replace_callback('/<!--###literal(\d+)###-->/is', array($this, 'restoreLiteral'), $tmplContent);
        // 添加安全代码
        $tmplContent =  '<?php if (!defined(\'THINK_PATH\')) exit();?>'.$tmplContent;
        // 优化生成的php代码
        $tmplContent = str_replace('?><?php','',$tmplContent);
        // 模版编译过滤标签,替换各种__XXX__常量
        Hook::listen('template_filter',$tmplContent);
        return strip_whitespace($tmplContent);
    }


    protected function parseInclude($content, $extend = true) {
        // 解析继承
        if($extend)
            $content    =   $this->parseExtend($content);
        // 解析布局
        $content    =   $this->parseLayout($content);
        //PeA:模版编译过滤标签,替换各种__XXX__常量
        Hook::listen('template_filter',$content);
        // 读取模板中的include标签
        $find       =   preg_match_all('/'.$this->config['taglib_begin'].'include\s(.+?)\s*?\/'.$this->config['taglib_end'].'/is',$content,$matches);
        if($find) {
            for($i=0;$i<$find;$i++) {
                $include    =   $matches[1][$i];
                $array      =   $this->parseXmlAttrs($include);
                $file       =   $array['file'];
                unset($array['file']);
                $content    =   str_replace($matches[0][$i],$this->parseIncludeItem($file,$array,$extend),$content);
            }
        }
        return $content;
    }

然后我们就可以放心大胆的使用模板常量做为模板继承或Include的路径了!

定义模板常量其实也有小技巧,参考我的另一篇文章

  • 浏览:1700
  • 评论:0

发表新的回复