1. 程式人生 > >在TP5中,模板裡的include file裡使用變數的解決方案

在TP5中,模板裡的include file裡使用變數的解決方案

在一個專案中遇到一個需求,需要在模板檔案上一層加一個檔案,類似 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!
一點小東西,希望能幫到需要的朋友,如果大佬們有更好的方法,或者我這裡有問題,都歡迎指導和指正!