- 77浏览
- 2022-10-31
在一个项目中遇到一个需求,需要在模板文件上一层加一个文件,类似 dir/index/index.html这种东西,尴尬的是,这个dir是不固定的,所以我希望的是,在模板里能使用 {include file="$dir/index/index"}
,像什么{include file=$dir."/index/index"} 或者 {include file="{$dir}/index/index"} 或者 {include file="$dir.index/index"}
,还有什么单双引号拼接之类的都试过,然而并不支持。
所以我想到了下面几种种方式:
1.提前定义好
$dir=‘dir/index/index’
然后直接写在{include file="$dir"}
,但是这样就出现一个问题,我页面上那么多地方需要用到引入文件,不可能都定义一次,否定!
2.拼接引入文件,这样可以使用变量,但是不会被渲染,导致我引入文件里的变量等全部需要用原生PHP写,这改动对我来说太大了,否定!
3.改动框架源文件,让这里可以识别变量。然后我找到渲染模板替换文件,在根目录下的:thinkphp/library/think/Template.phpl里有个方法:
public function parse(&$content)
{
// 内容为空不解析
if (empty($content)) {
return;
}
// 替换literal标签内容
$this->parseLiteral($content);
// 解析继承
$this->parseExtend($content);
// 解析布局
$this->parseLayout($content);
// 检查include语法
$this->parseInclude($content);
// 替换包含文件中literal标签内容
$this->parseLiteral($content);
// 检查PHP语法
$this->parsePhp($content);
// 获取需要引入的标签库列表
// 标签库只需要定义一次,允许引入多个一次
// 一般放在文件的最前面
// 格式:<taglib name="html,mytag..." />
// 当TAGLIB_LOAD配置为true时才会进行检测
if ($this->config['taglib_load']) {
$tagLibs = $this->getIncludeTagLib($content);
if (!empty($tagLibs)) {
// 对导入的TagLib进行解析
foreach ($tagLibs as $tagLibName) {
$this->parseTagLib($tagLibName, $content);
}
}
}
// 预先加载的标签库 无需在每个模板中使用taglib标签加载 但必须使用标签库XML前缀
if ($this->config['taglib_pre_load']) {
$tagLibs = explode(',', $this->config['taglib_pre_load']);
foreach ($tagLibs as $tag) {
$this->parseTagLib($tag, $content);
}
}
// 内置标签库 无需使用taglib标签导入就可以使用 并且不需使用标签库XML前缀
$tagLibs = explode(',', $this->config['taglib_build_in']);
foreach ($tagLibs as $tag) {
$this->parseTagLib($tag, $content, true);
}
// 解析普通模板标签 {$tagName}
$this->parseTag($content);
// 还原被替换的Literal标签
$this->parseLiteral($content, true);
return;
}
这里的 $this->parseInclude($content);
就是引入相关功能代码!进入后是如下代码:
private function parseInclude(&$content)
{
$regex = $this->getRegex('include');
$func = function ($template) use (&$func, &$regex, &$content) {
if (preg_match_all($regex, $template, $matches, PREG_SET_ORDER)) {
foreach ($matches as $match) {
$array = $this->parseAttr($match[0]);
$file = $array['file'];
unset($array['file']);
// 分析模板文件名并读取内容
$parseStr = $this->parseTemplateName($file);
foreach ($array as $k => $v) {
// 以$开头字符串转换成模板变量
if (0 === strpos($v, '$')) {
$v = $this->get(substr($v, 1));
}
$parseStr = str_replace('[' . $k . ']', $v, $parseStr);
}
$content = str_replace($match[0], $parseStr, $content);
// 再次对包含文件进行模板分析
$func($parseStr);
}
unset($matches);
}
};
// 替换模板中的include标签
$func($content);
return;
}
其中的$parseStr = $this->parseTemplateName($file);
就是在把file=""的内容放进去解析,OK,我们再进入看看:
private function parseTemplateName($templateName)
{
$array = explode(',', $templateName);
$parseStr = '';
foreach ($array as $templateName) {
if (empty($templateName)) {
continue;
}
if (0 === strpos($templateName, '$')) {
//支持加载变量文件名
$templateName = $this->get(substr($templateName, 1));
}
$template = $this->parseTemplateFile($templateName);
if ($template) {
// 获取模板文件内容
$parseStr .= file_get_contents($template);
}
}
return $parseStr;
}
好的,就是这里!下面还有变量相关的代码,有兴趣的朋友可以打印看看,这里不再赘述。我不改动源码,在这段代码前面加一点就行,代码如下:
$arr = explode('/',$templateName);
$str = '';
foreach($arr as $v){
if(0 === strpos($v,'$')){
$str .= $this->get(substr($v, 1)).'/';
}else{
$str .= $v.'/';
}
}
$templateName = substr($str,0,-1);
原理很简单,就是把file里的内容经过"/"分割,然后循环判断是否为变量,是变量这去拿变量的值,然后重新拼接在一起。这个操作会让下面源码里的变量判断失效,不过没关系,我们在这里已经转化过了。我没有去动源码,因为怕引出更多问题。
测试一下,OK!
一点小东西,希望能帮到需要的朋友,如果大佬们有更好的方法,或者我这里有问题,都欢迎指导和指正!
版权声明:
1、本文系转载,版权归原作者所有,旨在传递信息,不代表看本站的观点和立场。
2、本站仅提供信息发布平台,不承担相关法律责任。
3、若侵犯您的版权或隐私,请联系本站管理员删除。
4、本文由会员转载自互联网,如果您是文章原创作者,请联系本站注明您的版权信息。