您好,登錄后才能下訂單哦!
這篇文章主要介紹ThinkPHP中模板引擎是什么,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!
模板引擎由來
早期做PHP開發WEB應用都是把PHP代碼和HTML模板混在一起,模板引擎的誕生主要就是為了解決后端與前端的完全分離(現在來看其實是屬于不完全分離)的問題,讓開發與美工可以分工合作(雖然實際上最終模板工作大多仍然是由后端開發人員完成),從而提高開發效率和便于維護。
伴隨著PHP的快速成長,模板引擎也越來越多,但大致分為解釋型和編譯型兩種,目前主流的模板引擎大多數是編譯型的,也就是會先把模板編譯成PHP文件執行,只要模板文件本身不變化,就不需要重新編譯,例如老牌的Smarty。解釋型的模板引擎每次執行的時候都會進行模板解析流程,例如小強(tinybutstrong)。
ThinkPHP從一開始就內置了一個基于XML標簽庫技術的編譯型模板引擎,早期參考自Struts,并且不斷在汲取新的思想不斷進化。
如何選擇模板引擎
目前主流框架都帶有模板引擎組件或者封裝了模板引擎的實現,因此選擇內置的解決方案是最佳之選,功能和穩定性都有保證。目前最流行的模板引擎當屬Laravel自帶的Blade模板引擎,以及Symfony自帶的Twig模板引擎。
通過安裝模板引擎擴展,你可以在ThinkPHP中輕松使用包括Angular、Twig和Blade在內的模板引擎,甚至完全不使用模板引擎而是直接用PHP文件作為模板。
因為近幾年三大前端框架(React/Vue/Angular)的流行,前后端分離開發逐漸成為主流,因此從ThinkPHP5.0開始定位為API開發而設計,導致模板引擎的概念已經被弱化了。ThinkPHP5.1版本的模板引擎進行過一次內部的重構,使得模板標簽更加易用和接近PHP語法。
至少對于大部分新的應用來說,應該選擇更主流的前后端分離設計,盡量減輕服務端的壓力,也更方便前后端單獨測試。你會在市面上不經意的看到采用Vue和ThinkPHP的產品(之前幾期的ThinkPHP開發者周刊曾經報道過幾個)。如果是維護一些老項目尤其是內容管理產品的時候,仍然可能會用到模板引擎。
鑒于這種情況,下一個版本的ThinkPHP框架將不會內置模板引擎,但有需要使用模板引擎的開發者仍然可以使用官方獨立出來的think-template類庫,具體使用可以參考這篇文章。
后面的篇幅,我們主要來總結下ThinkPHP內置的模板引擎的使用和技巧。
模板執行流程
系統內部的模板引擎調用關系如下:
視圖(View) <=> 模板驅動(Driver) <=> 模板引擎(Template)
視圖和模板引擎之間增加了一個驅動層,所以可以很方便的替換其它的模板引擎。通常我們在控制器中調用的assign/fetch等方法其實都是調用的think\View類的方法。當然,如果有必要,你也完全可以直接在控制器中操作模板引擎類,只是不方便切換其它模板引擎。
以fetch方法為例,我們看下最終的調用過程:
think\Controller->fetch(); think\View->fetch(); think\view\driver\Think->fetch(); think\Template->fetch();
如果你調用fetch方法的時候沒有傳入要渲染的完整模板文件名,則會在第三步的時候自動識別要渲染的模板文件。
很顯然,最關鍵是最后一步,模板編譯和執行的流程則全部由
think\Template->fetch();
方法完成,這個環節大體又可以分成幾個流程。
1、判斷和讀取頁面渲染緩存
如果當前模板設置了頁面輸出緩存并且已經渲染輸出過,如果是則會讀取緩存中的輸出內容直接輸出。
if (!empty($this->config['cache_id']) && $this->config['display_cache']) { // 讀取渲染緩存 $cacheContent = $cache->get($this->config['cache_id']); if (false !== $cacheContent) { echo $cacheContent; return; } }
2、定位模板文件
定位實際的模板文件操作由模板引擎類的parseTemplateFile方法實現,這個方法的邏輯其實和視圖驅動類的parseTemplate方法是類似的,如果最終的模板文件不存在則會拋出一個模板文件不存在的異常。
$template = $this->parseTemplateFile($template);
3、判斷編譯緩存
如果當前的模板文件已經編譯過,會判斷緩存是否還有效,有效的話就不用重復解析直接讀取緩存的解析內容。由checkCache方法負責完成。
if (!$this->checkCache($cacheFile)) { // 緩存無效 重新模板編譯 $content = file_get_contents($template); $this->compiler($content, $cacheFile); }
4、模板編譯并緩存
這一步驟是模板引擎最核心的環節,也是功能最復雜的地方,由compiler方法負責完成,主要是解析當前模板文件中的模板標簽語法為PHP可執行代碼,然后生成一個模板解析緩存文件,也就是所謂的模板“編譯”,其中使用了大量的正則表達式替換技術,雖然正則解析有一定的性能開銷,但得益于一次解析多次調用的緩存原理,基本上模板解析的性能開銷不會影響實際使用的性能。
模板編譯方法的關鍵代碼是parse方法,parse方法負責對模板文件中的標簽進行解析,然后寫入編譯緩存文件,編譯緩存默認使用的是文件緩存,支持擴展。
5、讀取編譯緩存
模板編譯的過程只是生成了模板編譯緩存文件,并沒有真正載入模板,這一步驟就是載入模板編譯緩存,然后導入模板變量。實現方法可以參考think\template\driver\File類的read方法。
public function read($cacheFile, $vars = []) { $this->cacheFile = $cacheFile; if (!empty($vars) && is_array($vars)) { // 模板陣列變量分解成為獨立變量 extract($vars, EXTR_OVERWRITE); } //載入模版緩存文件 include $this->cacheFile; }
6、緩存頁面輸出
如果當前模板渲染的時候開啟了頁面輸出緩存,就會這一步生成頁面渲染后的輸出緩存。
模板編譯原理
我們來了解下ThinkPHP的模板引擎的實現原理。前面提到過,ThinkPHP的模板引擎最早源于Struts的設計理念,基于XML和標簽庫的技術實現。在設計模板語言的時候使用系統固定的標簽來實現普通的變量輸出功能(所以稱之為普通標簽),而利用XML標簽庫技術實現的動態標簽用于變量的控制或者條件判斷輸出。
普通標簽的解析是由think\Template類的parseTag方法完成的,主要實現了下面幾個模板功能:
·變量輸出(包括系統變量);
·函數過濾;
·變量運算;
·三元運算;
·執行函數以及輸出結果;
·模板注釋。
標簽庫采用的是動態擴展的設計方案,采用了類似XML的閉合/開放定義方式(這個其實也是目前模板引擎的一個局限所在),例如下面的這個:
// 閉合類型標簽 <tagLib:tagName name="value" > ... </tagLib:tagName> // 開放類型標簽 <tagLib:tagName name="value" />
tagLib就代表了一個標簽庫(類),后面的tagName標簽就表示該標簽庫下面的某個標簽(通常對應了標簽庫類的某個方法),后面的屬性就是該標簽支持的屬性定義。具體該標簽的屬性和功能則完全由標簽庫類的這個方法來決定。
可以在模板開頭明確指出,當前模板使用了哪些標簽庫
{taglib name="html,article" /}
所以要擴展模板引擎的功能只需要通過擴展一個標簽庫類就可以了。大多數的內容管理系統都會定義一套自己的模板二次開發標簽,利用標簽庫功能就可以很方便的定義一套屬于自己的標簽功能。
系統內置了一套標簽庫Cx,主要用于文件包含、條件控制、循環輸出等功能。內置標簽庫在使用的時候無需引入,而且在使用的時候可以省略標簽庫前綴,例如:
{foreach $list as $key=>$vo } {$vo.id}:{$vo.name} {/foreach}
這個模板語法相信PHP開發的很容易上手,上面的標簽解析由think\template\taglib\Cx類的tagForeach方法完成,該方法的返回值是一個字符串,其實就是最終會解析成的一段包含變量的PHP可執行代碼。
到這里,模板引擎的執行過程和原理現在基本就明白了,剩下的就是模板標簽的解析細節,考驗的就是正則表達式的掌握程度了。本文就不做深入了,有興趣的朋友可以去看一些正則表達式的相關資料(例如這本《正則指引》,開發者周刊第14期也提供了一些在線的正則工具)。
遵循的原則
使用模板引擎,要盡量遵循幾個重要的原則。
不要在模板文件中添加任何的業務邏輯
模板的作用主要是進行模板變量的控制和輸出,不要在模板文件中添加業務邏輯代碼。
明確指定渲染模板
養成明確指定渲染模板的好習慣,避免當方法名發生變化,或者被其它方法調用的時候發生錯誤。也不易受模板命名規范的影響。
變量統一賦值
使用assign方法或者在view助手函數的時候,統一一次傳入模板變量。不要多次賦值,以免混亂。
系統變量無需賦值到模板
對于系統變量(包括請求變量、$_SESSION和$_SERVER等系統變量)無需進行模板變量賦值,可以直接在模板中輸出。
常見問題
這里總結一下經常會遇到的一些常見問題。
修改定界符
可以通過模板配置文件修改模板標簽的定界符。
例如,修改普通標簽定界符
'tpl_begin' => '{{', // 模板引擎普通標簽開始標記 'tpl_end' => '}}', // 模板引擎普通標簽結束標記
標簽庫標簽定界符
'taglib_begin' => '<{', // 標簽庫標簽開始標記 'taglib_end' => '}>', // 標簽庫標簽結束標記
保持原樣輸出
如果擔心模板標簽和JS代碼產生混淆,可以使用literal標簽
{literal} Hello,{$name}! {/literal}
頁面最終會直接輸出
Hello,{$name}!
避免輸出轉義
5.1版本為了避免XSS攻擊,默認對模板變量的輸出使用了安全轉義,默認的轉義函數是htmlentities,你可以通過更改default_filter配置改變默認的轉義函數。
如果你不需要對某個模板變量輸出進行轉義(例如包含了HTML代碼),可以使用:
{$data.content|raw}
分頁輸出就是一個需要輸出HTML的典型例子,因此必須增加|raw。
關于模板主題
新版取消了原來的模板主題功能,因為模板主題對模板引擎來說,其實無非是一個模板目錄,完全可以根據自己的需求控制。
例如
$theme = 'blue'; $this->fetch('/' . $theme. '/user/index');
或者動態設置模板引擎的view_path參數
$this->view->config('view_path', \think\facade\App::getModulePath(). 'view/'. $theme . '/');
如何關閉模板緩存
由于是編譯型模板引擎,模板標簽不能被直接執行,必須編譯成PHP語法后才能執行,因此不能關閉模板編譯緩存,模板引擎每次執行渲染的時候會檢測模板文件是否有變化,當模板文件的修改時間超過模板編譯緩存的修改時間后,模板引擎會自動更新編譯緩存。
但你可以強制模板引擎每次都重新編譯,只需要在配置文件中設置
'tpl_cache' => false, // 關閉模板緩存
使用PHP作為模板引擎
如果不希望使用內置的模板引擎,直接使用PHP作為模板引擎,可以配置
'type' => 'php',
配置使用PHP作為模板引擎的話,是不會生成模板編譯緩存的。
如何使用第三方模板引擎
系統支持擴展其它的第三方模板引擎,你只需要開發一個模板引擎驅動,目前已經支持的第三方模板引擎包括Smarty、Twig和Blade。
如何跨模塊輸出模板
要渲染一個跨模塊的模板文件,你需要使用
// 渲染user模塊的模板文件 $this->fetch('User@order/index');
是否支持變量運算
可以直接在模板文件中進行變量運算而不需要在控制器中進行運算后再賦值都模板變量輸出。
{$score1+$score2} {$count++}
文件包含是否支持變量
include標簽可以支持傳入變量,但只能使用
{include file="$file" /}
而不能使用
{include file="file_$name" /}
可以支持模板輸出替換么
支持兩個方式對模板進行輸出替換,如果需要對模板文件的內容進行替換,可以配置:
'tpl_replace_string' => [ '__STATIC__'=>'/static', '__JS__' => '/static/javascript', ]
如果是對模板渲染輸出的內容進行替換,可以在控制器中使用視圖過濾功能:
public function index() { // 使用視圖輸出過濾 return $this->filter(function($content){ return str_replace("\r\n",'<br/>',$content); })->fetch(); }
模板繼承的block是否支持嵌套
目前模板繼承的block無法支持嵌套功能,你應該使用其它方式解決。
以上是“ThinkPHP中模板引擎是什么”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。