解决ThinkPHP模板常量解析失败

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

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

其原因有2

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

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

[code]
127.0.0.1/nut_shop/Public/jQuery.js
[/code]

而引用PHP文件则需要

[code]
./Public/nav.html
[/code]

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

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

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

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

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

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

[code]
.\ThinkPHP\Library\Think\Template.class.php
[/code]

流程如下:

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

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

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

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

[php]
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;
}
[/php]

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

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

  • 浏览:4278
  • 评论:0

发表新的回复