前些時間在看創智博客韓順平的Smarty模板引擎教程,再結合自己跟李炎恢第二季開發中CMS系統寫的tpl模板引擎。今天就寫一個迷你版的Smarty引擎,雖然說我並沒有深入分析過Smarty的源碼,但是對模板引擎的原理,還是有深刻的理解的。如果有什么還需要改進的地方,記得提出來。
一、什么是Smarty模板引擎:
Smarty是一個使用PHP寫出來的模板引擎,是目前業界最著名的PHP模板引擎之一。它分離了邏輯代碼和外在的內容,提供了一種易於管理和使用的方法,用來將原本與HTML代碼混雜在一起PHP代碼邏輯分離。簡單的講,目的就是要使PHP程序員同前端人員分離,使程序員改變程序的邏輯內容不會影響到前端人員的頁面設計,前端人員重新修改頁面不會影響到程序的程序邏輯,這在多人合作的項目中顯的尤為重要。(來自百度百科)
自己的理解是:
第一,有利於把前端開發與后台開發工作分離,利於分工合作;
第二,其緩存機制,有利於加快網站的訪問速度;
第三,模板標簽還可以一次編寫,到處調用,便利和簡潔性好;
二、下面就一起開發迷你版模板引擎吧
(1)首先先把已經做好的模板引擎給大家看一看,先使用,再開發
① 迷你版Smarty模板引擎目錄結構如下:
源代碼里面有很詳細的說明,請看下面
① 要開發一個模板引擎,最主要的有兩個類,分別是模板引擎入口類和模板解析類。
A.首先創建MiniSmarty目錄,然后新建一個文件名為MiniSmarty.class.php
其代碼如下:
/** * MiniSmarty模板引擎 * @link http://www.cnblogs.com/isuhua/ * @author 華仔_suhua <weibo.com/suhua123> * @package MiniSmarty * @version 0.0.0.1 */ class MiniSmarty { //模板文件 public $template_dir = 'templates'; //編譯文件 public $compile_dir = 'templates_c'; //緩存文件 public $cache_dir = 'cache'; //模板變量 public $_tpl_var = array(); //是否開啟緩存 public $caching = false; public function __construct() { $this->checkDir(); } //檢查目錄是否建好 private function checkDir() { if (!is_dir($this->template_dir)) { exit('模板文件目錄templates不存在!請手動創建'); } if (!is_dir($this->compile_dir)) { exit('編譯文件目錄templates_c不存在!請手工創建!'); } if (!is_dir($this->cache_dir)) { exit('緩存文件目錄'.$this->cache_dir.'不存在!請手工創建!'); } } //模板變量注入方法 public function assign($tpl_var, $var = null) { if (isset($tpl_var) && !empty($tpl_var)) { $this->_tpl_var[$tpl_var] = $var; } else { exit('模板變量名沒有設置好'); } } //文件編譯 public function display($file) { //模板文件 $tpl_file = $this->template_dir.'/'.$file; if (!file_exists($tpl_file)) { exit('ERROR:模板文件不存在!'); } //編譯文件 $parse_file = $this->compile_dir.'/'.md5($file).$file.'.php'; //只有當編譯文件不存在或者是模板文件被修改過了 //才重新編譯文件 if (!file_exists($parse_file) || filemtime($parse_file) < filemtime($tpl_file)) { include 'smarty_compile.class.php'; $compile = new Smarty_Compile($tpl_file); $compile->parse($parse_file); } //開啟了緩存才加載緩存文件,否則直接加載編譯文件 if ($this->caching) { //緩存文件 $cache_file = $this->cache_dir.'/'.md5($file).$file.'.html'; //只有當緩存文件不存在,或者編譯文件已被修改過 //重新生成緩存文件 if (!file_exists($cache_file) || filemtime($cache_file) < filemtime($parse_file)) { //引入緩存文件 include $parse_file; //緩存內容 $content = ob_get_clean(); //生成緩存文件 if (!file_put_contents($cache_file, $content)) { exit('緩存文件生成出錯!'); } } //載入緩存文件 include $cache_file; } else { //載入編譯文件 include $parse_file; } } }
B.然后再新建一個MiniSmarty模板引擎解析器類文件:MiniSmarty_Compile.class.php
其代碼如下:
<?php /** * MiniSmarty模板引擎 * @link http://www.cnblogs.com/isuhua/ * @author 華仔_suhua <weibo.com/suhua123> * @package MiniSmarty * @version 0.0.0.1 */ class MiniSmarty_Compile { //模板內容 private $content = ''; //構造函數 public function __construct($tpl_file) { $this->content = file_get_contents($tpl_file); } //解析普通變量,如把{$name}解析成$this->_tpl_var['name'] public function parseVar() { $pattern = '/\{\$([\w\d]+)\}/'; if (preg_match($pattern, $this->content)) { $this->content = preg_replace($pattern, '<?php echo \$this->_tpl_var["$1"]?>', $this->content); } } //這里可以自定義其他解析器... //模板編譯 public function parse($parse_file) { //調用普通變量解析器 $this->parseVar(); //這里可以調用其他解析器... //編譯完成后,生成編譯文件 if (!file_put_contents($parse_file, $this->content)) { exit('編譯文件生成出錯!'); } } } ?>
C.最后,還必須新建幾個目錄,分別是模板文件目錄templates、編譯文件目錄 template_c、緩存文件目錄cache。
如果你(ˇˍˇ) 想~一次性成功,就必須創建這幾個目錄,缺一不可。否則就會報錯,然后要求你手動創建。
D.來試試看吧,編寫demo.php,測試一下自定義的迷你版MiniSmarty模板引擎吧!
demo.php代碼如下:
//引入模板引擎 require 'MiniSmarty.class.php'; //實例化模板類 $minismarty = new MiniSmarty(); //緩存開關 $minismarty->caching = true; //定義變量 $webname = '迷你版Smarty測試'; $author = 'suhua'; $title = '這是一個測試標題'; $content = '這是一段測試內容'; //注入變量 $minismarty->assign('webname', $webname); $minismarty->assign('author', $author); $minismarty->assign('title', $title); $minismarty->assign('content', $content); //啟動編譯模板文件 $minismarty->display('demo.tpl');
測試前,請先看一下template、template_c 以及cache目錄各自的狀態,請看下圖:
E:打開瀏覽器,輸入http://localhost/MiniSmarty/demo.php,即可看到一下效果:
測試后,請再次看一下各目錄的狀態:
在template_c目錄和cache目錄下都分別多了一個xxxx.tpl.php和xxx.tpl.html文件,為什么呢?
答:這就是模板引擎非常重要的一個作用,編譯文件並生成靜態文件。對於如何實現的,這里不做解析,源碼已經給出,看看就懂。
---->至此表示自己開發的一個迷你版Smarty模板引擎成功!*\(^v^)/*
再次測試一下緩存功能是否生效了,首先修改demo.php中的代碼,改動如下:
把 $author = 'suhua'; 修改為 $author = 'xiwang';
改動過后,記得保存,然后再次刷新頁面,看出現什么狀況了?
結果是:沒有任何變化!這就正常了否則緩存功能沒有實現。
???為什么沒有任何變化呢
答:原因是我們在demo.php中開啟了緩存功能
//緩存開關 $minismarty->caching = true;
請看代碼。下面這段代碼是MiniSmarty.class.php里面的,下面就是根據你是否開啟緩存,決定是加載緩存文件還是編譯文件。因為這里開啟了,所以會直接加載緩存文件,所以就算你修改了原來的模板,依然沒變化。
//開啟了緩存才加載緩存文件,否則直接加載編譯文件 if ($this->caching) { //緩存文件 $cache_file = $this->cache_dir.'/'.md5($file).$file.'.html'; //只有當緩存文件不存在,或者編譯文件已被修改過 //重新生成緩存文件 if (!file_exists($cache_file) || filemtime($cache_file) < filemtime($parse_file)) { //引入緩存文件 include $parse_file; //緩存內容 $content = ob_get_clean(); //生成緩存文件 if (!file_put_contents($cache_file, $content)) { exit('緩存文件生成出錯!'); } } //載入緩存文件 include $cache_file; } else { //載入編譯文件 include $parse_file; }
如果我在demo.php中把緩存功能關了呢,結果會如何?
即改動如下:
//緩存開關 $minismarty->caching = false; //關閉緩存功能
此時,當你再次刷新頁面的時候,你會看到如下效果:
此時,作者一欄改變了,這說明了模板引擎此時並沒有去加載緩存文件,而是直接加載了編譯文件。所以會出現該效果。上面的代碼也說明了這一點。
其他細節在源碼中都有較詳細的注釋,在這里就不多說了,說一下其原理。
★ MiniSmarty模板引擎原理:(非常重要)
其原理也比較簡單
① 首先模板引擎會加載模板文件templates/demo.tpl,然后調用模板編譯類對其進行編譯解析(說白了就是變量替換或者標簽替換),編譯后就會生成編譯文件xxxx.tpl.php;
② 然后判斷緩存是否開啟,來決定是否生成緩存文件。其生成過程是:直接把xxx.tpl.php編譯文件加載進來,然后再從緩沖區取出所有內容,清空緩沖區,把內容寫入到緩存文件中xxx.tpl.html文件。
③ 模板文件demo.tpl是一個同時具有html和引擎標簽的復合文件,編譯文件xxx.tpl.php是把引擎標簽替換成php代碼,是具有php和html標簽的復合文件,緩存文件xxx.tpl.html文件就是一個純html的靜態文件;
至此,迷你版MiniSmarty模板引擎開發完成!
其中,如果還有其他不好的地方,希望各位指出!謝謝。
最后附上:MiniSmarty源碼.rar (點擊即可下載)