在TP5中,模板裡的include file裡使用變數的解決方案
阿新 • • 發佈:2019-02-11
在一個專案中遇到一個需求,需要在模板檔案上一層加一個檔案,類似 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!
一點小東西,希望能幫到需要的朋友,如果大佬們有更好的方法,或者我這裡有問題,都歡迎指導和指正!