久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

一個(gè)簡(jiǎn)單的PHP模板引擎

 fanfl0517 2019-10-27

PHP早期開發(fā)中通常是PHP代碼和HTML代碼混寫,這也使代碼中充斥著數(shù)據(jù)庫(kù)操作,邏輯處理等,。當(dāng)項(xiàng)目不大時(shí),,這樣的代碼還可以接受,,但是隨著項(xiàng)目不斷擴(kuò)大,,我們就會(huì)發(fā)現(xiàn)同一個(gè)文件中同時(shí)存在前端邏輯和后端處理,,當(dāng)邏輯越來(lái)越復(fù)雜時(shí),,代碼的可讀性和可維護(hù)性都會(huì)變得非常差,,以至于后來(lái)不得不進(jìn)行大規(guī)模的代碼重構(gòu)。所以后來(lái)就出現(xiàn)了代碼分層的思想,,盡量拆分開前端代碼和后端代碼,。

PHP模板引擎能解決這種混亂嗎?當(dāng)然可以,。但是呢,,即使你不用專門的模板引擎也可以寫出邏輯清晰的代碼,重點(diǎn)是要有分層的思想,,有專門的腳本去進(jìn)行數(shù)據(jù)獲取,,數(shù)據(jù)處理,邏輯處理等,,在展示頁(yè)面只進(jìn)行盡可能簡(jiǎn)單的邏輯處理即可,。既然這樣,那還有使用PHP模板引擎的必要嗎,?毫無(wú)疑問當(dāng)然有,,因?yàn)槟0逡娴墓δ懿粌H于此,。

那接下來(lái)就說(shuō)一下PHP模板引擎的主要作用:

1、它實(shí)現(xiàn)了一些自定義標(biāo)簽,,用于展示層的簡(jiǎn)單邏輯處理,,相較于不適用引擎的好處是代碼看起來(lái)不像是PHP代碼了,感覺上HTML代碼和PHP代碼完全分開了,,但這只是假象,,壞處是效率降低了,因?yàn)檫@樣的頁(yè)面需要專門的腳本解析后才能正確顯示,,解析的方法就是使用正則表達(dá)式替換,,這明顯降低了效率。到現(xiàn)在來(lái)看感覺PHP模板引擎有還不如沒有呢,,那為什么還要用它呢,,重點(diǎn)是他的下一個(gè)功能。

2,、文件緩存,,這是模板引擎在生產(chǎn)環(huán)境中提高效率的非常好的手段??梢杂迷陧?yè)面加載時(shí)所用數(shù)據(jù)量很大但不經(jīng)常變或者不需要實(shí)時(shí)更新,,即使延遲一會(huì)也無(wú)妨的頁(yè)面。我個(gè)人感覺文件緩存是PHP模板引擎的最重要的部分,。

接下來(lái)我們就寫一個(gè)簡(jiǎn)易的模板引擎(最后有完整文件代碼

首先我們先要計(jì)劃好我們的所需要的基礎(chǔ)類,,有Template類和Compile類。

在我們具體實(shí)現(xiàn)編譯功能之前先搭好一個(gè)空的骨架,,具體如下:

復(fù)制代碼
<?php/*** 模板引擎基礎(chǔ)類*/class Template{ private $config = array( 'suffix' => '.m', // 設(shè)置模板文件的后綴 'templateDir' => 'template/', // 設(shè)置模板所在的文件夾 'compileDir' => 'cache/', // 設(shè)置編譯后存放的目錄 'cache_html' => true, // 是否需要編譯成靜態(tài)的HTML文件 'suffix_cache' => '.html', // 設(shè)置編譯文件的后綴 'cache_time' => 7200, // 多長(zhǎng)時(shí)間自動(dòng)更新,,單位秒 'php_turn' => true, // 是否支持原生PHP代碼 'cache_control' => 'control.dat', 'debug' => false, ); private static $instance = null; private $value = array(); // 值棧 private $compileTool; // 編譯器 public $file; // 模板文件名,不帶路徑 public $debug = array(); // 調(diào)試信息 private $controlData = array(); public function __construct($config = array()) { $this->debug['begin'] = microtime(true); $this->config = $config + $this->config; if (! is_dir($this->config['templateDir'])) { exit('模板目錄不存在,!'); } if (! is_dir($this->config['compileDir'])) { mkdir($this->config['compileDir'], 0770); } $this->getPath(); include './Compile.php'; } /** *獲取絕對(duì)路徑 */ public function getPath() { $this->config['templateDir'] = strtr(realpath($this->config['templateDir']), '\\', '/').'/'; $this->config['compileDir'] = strtr(realpath($this->config['compileDir']), '\\', '/').'/'; } /** *取得模板引擎的實(shí)例 */ public static function getInstance() { if (is_null(self::$instance)) { self::$instance = new self(); } return self::$instance; } /* 設(shè)置模板引擎參數(shù) */ public function setConfig($key, $value = null) { if (is_array($key)) { $this->config = $key + $this->config; }else { $this->config[$key] = $value; } } /* 獲取當(dāng)前模板引擎配置,,僅供調(diào)試使用 */ public function getConfig($key = null) { if ($key) { return $this->config[$key]; }else { return $this->config; } } /** *注入單個(gè)變量 */ public function assign($key, $value) { $this->value[$key] = $value; } /** *注入數(shù)組變量 */ public function assignArray($array) { if (is_array($array)) { foreach($array as $k => $v) { $this->value[$k] = $v; } } } /** * 獲取模板文件完整路徑 */ public function path() { return $this->config['templateDir'].$this->file.$this->config['suffix']; } /** *判斷是否開啟了緩存 */ public function needCache() { return $this->config['cache_html']; } /** *顯示模板 */ public function show($file) { }}?>
復(fù)制代碼

從上邊的代碼中我們能發(fā)現(xiàn)對(duì)于模板文件不存在和編譯文件不存在處理方式不同,這也很容易理解,,如果你連模板文件都沒有有啥好編譯的,,但是你有模板文件沒編譯文件這也很正常,正常進(jìn)行編譯即可,。

如上所示,,我們首先想好了這個(gè)模板引擎需要什么配置,還有一些設(shè)置配置的方法和檢查配置的方法等,,而我們的核心方法show()還沒有實(shí)現(xiàn)呢,,先不著急,我們先去寫編譯類Compile,,如下所示:

復(fù)制代碼
<?phpclass Compile{    private $template;   // 待編譯的文件    private $content;   // 需要替換的文件    private $comfile;   // 編譯后的文件    private $left = '{';   // 左定界符    private $right = '}';   // 右定界符    private $value = array();   // 值棧    private $phpTurn;    private $T_P = array();   // 匹配正則數(shù)組    private $T_R = array();   // 替換數(shù)組    public function __construct($template, $compileFile, $config) {        $this->template = $template;        $this->comfile = $compileFile;        $this->content = file_get_contents($template);    }    public function compile() {        $this->c_var();        file_put_contents($this->comfile, $this->content);    }    public function c_var() {        $this->content = preg_replace($this->T_P, $this->T_R, $this->content);    }    public function __set($name, $value) {        $this->$name = $value;    }    public function __get($name) {        return $this->$name;    }}?>
復(fù)制代碼

從上面Compile類的構(gòu)造函數(shù)我們可以看出,,他需要模板文件路徑,,編譯文件路徑,和具體編譯時(shí)的配置參數(shù),,但是在這這個(gè)配置參數(shù)嗎,,沒有用到。之前說(shuō)過模板引擎主要使用的正則表達(dá)式來(lái)進(jìn)行匹配替換,,將模板文件編譯成能正確執(zhí)行的PHP文件,,這里使用數(shù)組存放正則匹配數(shù)組和替換數(shù)組來(lái)進(jìn)行整體替換。

接下來(lái)我們就簡(jiǎn)單實(shí)現(xiàn)幾個(gè)常用的標(biāo)簽,,先看怎么替換簡(jiǎn)單變量:

復(fù)制代碼
// \x7f-\xff表示ASCII字符從127到255,,其中\(zhòng)為轉(zhuǎn)義,作用是匹配漢字$this->T_P[] = '#\{\\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}#';$this->T_R[] = '<?php echo \$this->value['\\1']; ?>';
復(fù)制代碼

正如我們看到的,,上邊的那個(gè)是正則匹配,下邊的是替換,。但是我們沒有給編譯類的value變量賦值,,那這個(gè)替換能找到正確的值嗎?答案是能,,因?yàn)樗玫牟皇沁@個(gè)類的value用的是模板類的value,,接下來(lái)一會(huì)會(huì)講到。

然后我們?cè)诳纯丛趺磳?shí)現(xiàn)foreach標(biāo)簽,,這個(gè)很常用

復(fù)制代碼
$this->T_P[] = '#\{(loop|foreach)\s+\\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\s*\}#i';$this->T_P[] = '#\{\/(loop|foreach)\}#';
  $this->T_P[] = '#\{([k|v])\}#';
$this->T_R[] = '<?php foreach ((array)\$this->value['\\2'] as \$k => \$v) { ?>';$this->T_R[] = '<?php } ?>';
 $this->T_R[] = '<?php echo \$\\1?>';
復(fù)制代碼

這里用到的主要正則表達(dá)式的知識(shí)有:元組,、反向引用等,這些只要稍微看一下正則表達(dá)式基礎(chǔ)就能理解了,。

我們?cè)賮?lái)一個(gè)if else標(biāo)簽:

復(fù)制代碼
$this->T_P[] = '#\{\/(loop|foreach|if)\}#';$this->T_P[] = '#\{if (.*?)\}#';$this->T_P[] = '#\{(else if|elseif) (.*?)\}#';$this->T_P[] = '#\{else\}#';$this->T_R[] = '<?php } ?>';$this->T_R[] = '<?php if(\\1){ ?>';$this->T_R[] = '<?php }elseif(\\2){ ?>';$this->T_R[] = '<?php }else{ ?>';
復(fù)制代碼

我們將if的閉合標(biāo)簽和foreach的閉合標(biāo)簽放一塊了,。

現(xiàn)在我們已經(jīng)能編譯一些標(biāo)簽了我們就再轉(zhuǎn)回模板類,現(xiàn)在我們想一想要怎么展示呢,,這個(gè)才是我們的根本目的,。寫代碼之前先理一下思路:

1、判斷是否開啟了緩存,,如果是進(jìn)行第二步,,否則直接進(jìn)行編譯輸出。

2,、判斷是否需要更新緩存(判斷方式主要是緩存時(shí)間和編譯文件和模板文件的修改時(shí)間的關(guān)系),,如果是就進(jìn)行第三步,否則直接讀取緩存文件輸出,。

3,、重新編譯模板文件,并將編譯后的PHP文件輸出保存到靜態(tài)緩存文件中,。

簡(jiǎn)單來(lái)說(shuō)就是上邊的那三個(gè)步驟,,具體實(shí)現(xiàn)如下:

復(fù)制代碼
/** *是否需要重新生成靜態(tài)文件 */ public function reCache($file) { $flag = true; $cacheFile = $this->config['compileDir'].md5($file).$this->config['suffix_cache']; if ($this->config['cache_html'] === true) { $timeFlag = (time() - @filemtime($cacheFile)) < $this->config['cache_time'] ? true : false; if (is_file($cacheFile) && filesize($cacheFile) > 1 && $timeFlag && filemtime($compileFile) >= filemtime($this->path())) { $flag = false; }else { $flag = true; } } return $flag; } /** *顯示模板 */ public function show($file) { $this->file = $file; if (! is_file($this->path())) { exit('找不到對(duì)應(yīng)的模板,!'); } $compileFile = $this->config['compileDir'].md5($file).'.php'; $cacheFile = $this->config['compileDir'].md5($file).$this->config['suffix_cache']; extract($this->value, EXTR_OVERWRITE); if ($this->config['cache_html'] === true) { if ($this->reCache($file) === true) { $this->debug['cached'] = 'false'; $this->compileTool = new Compile($this->path(), $compileFile, $this->config); if ($this->needCache()) {ob_start();} if (! is_file($compileFile) || filemtime($compileFile) < filemtime($this->path())) { $this->compileTool->value = $this->value; $this->compileTool->compile(); include $compileFile; }else { include $compileFile; } if ($this->needCache()) { $message = ob_get_contents(); file_put_contents($cacheFile, $message); } }else { readfile($cacheFile); $this->debug['cached'] = 'true'; } }else { if (! is_file($compileFile) || filemtime($compileFile) < filemtime($this->path())) { $this->compileTool = new Compile($this->path(), $compileFile, $this->config); $this->compileTool->value = $this->value; $this->compileTool->compile(); include $compileFile; }else { include $compileFile; } } $this->debug['spend'] = microtime(true) - $this->debug['begin']; $this->debug['count'] = count($this->value); }
復(fù)制代碼

上邊的代碼基本是按照上述的三個(gè)步驟來(lái)進(jìn)行的,好好看一下不難理解,。

接下來(lái)就是模板文件了:

復(fù)制代碼
<html>{$data},{$person}<br/>列表一:<br/><ul>{foreach $arr1}<li>$v</li>{/foreach}</ul><br/>列表二:<br/><ul>{loop $arr2}<li>$v</li>{/loop}</ul>{if $a == '1'}a等于1{elseif $a == '2'}a等于2{else}a不等于1也不等于2{/if}</html>
復(fù)制代碼

這個(gè)模板文件主要測(cè)試了之前我們事先的模板標(biāo)簽,。

下面寫一個(gè)測(cè)試文件:

復(fù)制代碼
<?phpinclude_once './Template.php';$tpl = new Template();$tpl->assign('data', 'hello');$tpl->assign('person', 'world!');$tpl->assign('arr1', array('123','456','789'));$tpl->assign('arr2', array('abc', 'def', 'ghi'));$tpl->assign('a', '2');$tpl->show('member');?>
復(fù)制代碼

這就是一個(gè)簡(jiǎn)單的測(cè)試我們的模板引擎能不能用的測(cè)試用例。

下面我們看看完整代碼吧:

復(fù)制代碼
<?php/*** 模板引擎基礎(chǔ)類*/class Template{    private $config = array(        'suffix' => '.m',      // 設(shè)置模板文件的后綴        'templateDir' => 'template/',    // 設(shè)置模板所在的文件夾        'compileDir' => 'cache/',    // 設(shè)置編譯后存放的目錄        'cache_html' => true,    // 是否需要編譯成靜態(tài)的HTML文件        'suffix_cache' => '.html',    // 設(shè)置編譯文件的后綴        'cache_time' => 7200,    //  多長(zhǎng)時(shí)間自動(dòng)更新,,單位秒        'php_turn' => true,   // 是否支持原生PHP代碼        'cache_control' => 'control.dat',        'debug' => false,    );    private static $instance = null;    private $value = array();   // 值棧    private $compileTool;   // 編譯器    public $file;     // 模板文件名,,不帶路徑    public $debug = array();   // 調(diào)試信息    private $controlData = array();    public function __construct($config = array())    {        $this->debug['begin'] = microtime(true);        $this->config = $config + $this->config;        if (! is_dir($this->config['templateDir'])) {            exit('模板目錄不存在!');        }        if (! is_dir($this->config['compileDir'])) {            mkdir($this->config['compileDir'], 0770);        }        $this->getPath();        include './Compile.php';    }    /**    *獲取絕對(duì)路徑    */    public function getPath() {        $this->config['templateDir'] = strtr(realpath($this->config['templateDir']), '\\', '/').'/';        $this->config['compileDir'] = strtr(realpath($this->config['compileDir']), '\\', '/').'/';    }    /**    *取得模板引擎的實(shí)例    */    public static function getInstance() {        if (is_null(self::$instance)) {            self::$instance = new self();        }        return self::$instance;    }    /* 設(shè)置模板引擎參數(shù) */    public function setConfig($key, $value = null) {        if (is_array($key)) {            $this->config = $key + $this->config;        }else {            $this->config[$key] = $value;        }    }    /* 獲取當(dāng)前模板引擎配置,,僅供調(diào)試使用 */    public function getConfig($key = null) {        if ($key) {            return $this->config[$key];        }else {            return $this->config;        }    }    /**    *注入單個(gè)變量    */    public function assign($key, $value) {        $this->value[$key] = $value;    }    /**    *注入數(shù)組變量    */    public function assignArray($array) {        if (is_array($array)) {            foreach($array as $k => $v) {                $this->value[$k] = $v;            }        }    }    /**     * 獲取模板文件完整路徑     */    public function path() {        return $this->config['templateDir'].$this->file.$this->config['suffix'];    }    /**    *判斷是否開啟了緩存    */    public function needCache() {        return $this->config['cache_html'];    }    /**    *是否需要重新生成靜態(tài)文件    */    public function reCache($file) {        $flag = true;        $cacheFile = $this->config['compileDir'].md5($file).$this->config['suffix_cache'];        if ($this->config['cache_html'] === true) {            $timeFlag = (time() - @filemtime($cacheFile)) < $this->config['cache_time'] ? true : false;            if (is_file($cacheFile) && filesize($cacheFile) > 1 && $timeFlag && filemtime($compileFile) >= filemtime($this->path())) {                $flag = false;            }else {                $flag = true;            }        }        return $flag;    }    /**    *顯示模板    */    public function show($file) {        $this->file = $file;        if (! is_file($this->path())) {            exit('找不到對(duì)應(yīng)的模板,!');        }        $compileFile = $this->config['compileDir'].md5($file).'.php';        $cacheFile = $this->config['compileDir'].md5($file).$this->config['suffix_cache'];        extract($this->value, EXTR_OVERWRITE);        if ($this->config['cache_html'] === true) { // 開啟緩存的處理邏輯            if ($this->reCache($file) === true) { // 需要更新緩存的處理邏輯                $this->debug['cached'] = 'false';                $this->compileTool = new Compile($this->path(), $compileFile, $this->config);                if ($this->needCache()) {ob_start();} // 打開輸出控制緩沖                if (! is_file($compileFile) || filemtime($compileFile) < filemtime($this->path())) {                    $this->compileTool->value = $this->value;                    $this->compileTool->compile();                    include $compileFile;                }else {                    include $compileFile;                }                if ($this->needCache()) {                    $message = ob_get_contents(); // 獲取輸出緩沖中的內(nèi)容(在include編譯文件的時(shí)候就有輸出了)                    file_put_contents($cacheFile, $message);                }            }else {                readfile($cacheFile);                $this->debug['cached'] = 'true';            }        }else {            if (! is_file($compileFile) || filemtime($compileFile) < filemtime($this->path())) {                $this->compileTool = new Compile($this->path(), $compileFile, $this->config);                $this->compileTool->value = $this->value;                $this->compileTool->compile();                include $compileFile;            }else {                include $compileFile;            }        }        $this->debug['spend'] = microtime(true) - $this->debug['begin'];        $this->debug['count'] = count($this->value);        //$this->debug_info();    }    public function debug_info() {        if ($this->config['debug'] === true) {            echo PHP_EOL, '---------debug info---------', PHP_EOL;            echo '程序運(yùn)行日期:', date('Y-m-d H:i:s'), PHP_EOL;            echo '模板解析耗時(shí):', $this->debug['spend'], '秒', PHP_EOL;            echo '模板包含標(biāo)簽數(shù)目:', $this->debug['count'], PHP_EOL;            echo '是否使用靜態(tài)緩存:', $this->debug['cached'], PHP_EOL;            echo '模板引擎實(shí)例參數(shù):', var_dump($this->getConfig());        }    }    /**    *清理緩存的HTML文件    */    public function clean($path = null) {        if ($path === null) {            $path = $this->config['compileDir'];            $path = glob($path.'* '.$this->config['suffix_cache']);        }else {            $path = $this->config['compileDir'].md5($path).$this->config['suffix_cache'];        }        foreach((array)$path as $v) {            unlink($v);        }    }}?>
復(fù)制代碼
復(fù)制代碼
<?phpclass Compile{ private $template; // 待編譯的文件 private $content; // 需要替換的文件 private $comfile; // 編譯后的文件 private $left = '{'; // 左定界符 private $right = '}'; // 右定界符 private $value = array(); // 值棧 private $phpTurn; private $T_P = array(); // 匹配正則數(shù)組 private $T_R = array(); // 替換數(shù)組 public function __construct($template, $compileFile, $config) { $this->template = $template; $this->comfile = $compileFile; $this->content = file_get_contents($template); if ($config['php_turn'] === true) { $this->T_P[] = '#<\?(=|php|)(.+?)\?#is'; $this->T_R[] = '<?\1\2?>'; } // 變量匹配 // \x7f-\xff表示ASCII字符從127到255,其中\(zhòng)為轉(zhuǎn)義,,作用是匹配漢字 $this->T_P[] = '#\{\\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}#'; // foreach標(biāo)簽盤匹配 $this->T_P[] = '#\{(loop|foreach)\s+\\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\s*\}#i'; $this->T_P[] = '#\{\/(loop|foreach|if)\}#'; $this->T_P[] = '#\{([k|v])\}#'; // if else標(biāo)簽匹配 $this->T_P[] = '#\{if (.*?)\}#'; $this->T_P[] = '#\{(else if|elseif) (.*?)\}#'; $this->T_P[] = '#\{else\}#'; $this->T_P[] = '#\{(\#|\*)(.*?)(\#|\*)\}#'; $this->T_R[] = '<?php echo \$this->value['\\1']; ?>'; $this->T_R[] = '<?php foreach ((array)\$this->value['\\2'] as \$k => \$v) { ?>'; $this->T_R[] = '<?php } ?>'; $this->T_R[] = '<?php echo \$\\1?>'; $this->T_R[] = '<?php if(\\1){ ?>'; $this->T_R[] = '<?php }elseif(\\2){ ?>'; $this->T_R[] = '<?php }else{ ?>'; $this->T_R[] = ''; } public function compile() { $this->c_var(); //$this->c_staticFile(); file_put_contents($this->comfile, $this->content); } public function c_var() { $this->content = preg_replace($this->T_P, $this->T_R, $this->content); } /* 對(duì)引入的靜態(tài)文件進(jìn)行解析,,應(yīng)對(duì)瀏覽器緩存 */ public function c_staticFile() { $this->content = preg_replace('#\{\!(.*?)\!\}#', '<script src=\1'.'?t='.time().'></script>', $this->content); } public function __set($name, $value) { $this->$name = $value; } public function __get($name) { return $this->$name; }}?>
復(fù)制代碼

模板文件member.m代碼:

復(fù)制代碼
<html>{$data},{$person}<br/>列表一:<br/><ul>{foreach $arr1}<li>$v</li>{/foreach}</ul><br/>列表二:<br/><ul>{loop $arr2}<li>$v</li>{/loop}</ul>{if $a == '1'}a等于1{elseif $a == '2'}a等于2{else}a不等于1也不等于2{/if}</html>
復(fù)制代碼

測(cè)試用例:

復(fù)制代碼
<?phpinclude_once './Template.php';$tpl = new Template();$tpl->assign('data', 'hello');$tpl->assign('person', 'world!');$tpl->assign('arr1', array('123','456','789'));$tpl->assign('arr2', array('abc', 'def', 'ghi'));$tpl->assign('a', '2');$tpl->show('member');?>
復(fù)制代碼

本文內(nèi)容大部分來(lái)自于《PHP核心技術(shù)與最佳實(shí)踐》的第六章。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多