程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> PHP--關於模板的原理和解析,php--模板解析

PHP--關於模板的原理和解析,php--模板解析

編輯:關於PHP編程

PHP--關於模板的原理和解析,php--模板解析


此內容用作筆記,以備日後查看,此內容為學習李炎恢課程而來,並非自己所創,如有問題請私信~

將PHP代碼和靜態HTML代碼進行分離,使代碼的可讀性和維護性得到顯著提高。

使用模板引擎:

    我們所說的模板是Web模板,是主要由HTML標記組成的語言來編寫的頁面,但也有如何表示包含動態生成內容的方式(解析標簽)。模板引擎是一種軟件庫,允許我們從模板生成HTML代碼,並指定要包含的動態內容。

  模板引擎的特點:

  1.鼓勵分離:讓更個系統的可讀性和維護性得到提高。
  2.促進分工:使得程序員和美工去專心處理自己的設計。
  3.比PHP更容易解析:編譯文件和緩存文件加載更快、占資源更少。
  4.增加安全性:可限制模板設計師進行不安全的操作的能力避免誤刪誤訪問等。

模板處理的流程圖

  

 

創建模板:

  1、創建初始模板所需要的文件夾和文件。

  a) index.php主文件,用於編寫業務邏輯。
  b) template.inc.php模板初始化文件,用於初始模版信息。
  c) templates目錄存放所有的模板文件。
  d) templates_c目錄存放所有編譯文件。
  e) cache目錄存放所有緩存文件。
  f) includes目錄存放所有的類文件。
  g) config目錄存放模板系統變量配置文件。

  

  以下是源碼:

主文件 index.php  

<?php
   //index.php

  //設置編碼為UTF-8
  header('Content-Type:text/html;Charset=utf-8');
  //網站根目錄
  define('ROOT_PATH', dirname(__FILE__));
  //存放模板文件夾
  define('TPL_DIR', ROOT_PATH.'/templates/');
  //編譯文件夾
  define('TPL_C_DIR', ROOT_PATH.'/templates_c/');
  //緩存文件夾
  define('CACHE_DIR', ROOT_PATH.'/cache/');
  //定義緩存狀態
  define('IS_CACHE',true);
  //設置緩存狀態開關
  IS_CACHE ? ob_start() : null;

  include ROOT_PATH.'/includes/Templates.class.php';

  $_name = '方塊李';
    
    $array = array(1,2,3,4,5,6);
    $_tpl = new Templates();
    $_tpl->assign('name', $_name);
    $_tpl->assign('a', 5>4);
    $_tpl->assign('array', $array);
    //顯示
    $_tpl->display('index.tpl');
?>

模板文件 HTML

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title><!--{webname}--></title>

</head>
<body>
{include "test.php"}
<!-- 這是HTML的注釋 -->
{#}這是一條PHP的注釋,在HTML頁面裡是不顯示的,只會在生成的編譯文件裡顯示{#}
我將被index.php導入
{$name}這個標簽必須經過Parser.class.php這個解析類來解析它1
<br />
這裡的內容改變了,為什麼?
<br />
{if $a}
顯示一號皮膚
{else}
顯示二號皮膚
{/if}
<br />
{foreach $array(key,value)}
{@key}....{@value} <br />
{/foreach}
</body>
</html>

  

模板類:

         //Templates.class.php   
	class Templates {
	    //創建一個存放數組的字段
	    private $_vars = array();
	    private $_config = array();
	    //創建一個構造方法
	    public function __construct(){
	        if(!is_dir(TPL_DIR) || !is_dir(TPL_C_DIR) || !is_dir(CACHE_DIR) ){
	            exit('ERROR:模板文件夾或者編譯文件夾或者緩存文件夾沒有創建!');
	        }
	        //獲取系統變量
	        $_sxe = simplexml_load_file(ROOT_PATH.'/config/profile.xml');
	        $_taglib = $_sxe->xpath('/root/taglib');
	        foreach($_taglib as $_tag){
	            $this->_config["$_tag->name"] = $_tag->value;
	        }
	    }
	  
	    
	    //創建變量注入方法
	    /**
	     * assign()變量注入方法
	     * @param  $_var 要注入的變量名,對應.tpl文件中的需要替換的變量 
	     * @param  $_values 要注入的變量值
	     */
	    public function assign($_var,$_values){
	        if(isset($_var) && !empty($_var)){
	            $this->_vars[$_var] = $_values;
	            
	        }else{
	            exit('ERROR:請設置變量名!');
	        }
	        
	    }
	    
	    
	    //創建一個顯示方法,用來顯示編譯後的文件
	    public function display($_file){
	        //設置模板文件的路徑
	        $_tplFile = TPL_DIR.$_file;
	        //判斷模板文件是否存在
	        if(!file_exists($_tplFile)){
	            exit('ERROR:模板文件不存在');
	        }
	        //設置編譯文件名
	        $_parFile  = TPL_C_DIR.md5($_file).$_file.'.php';
	        //設置緩存文件名
	        $_cacheFile = CACHE_DIR.md5($_file).$_file.'.html';
	        //判斷緩存狀態
	        if(IS_CACHE){
	            //判斷緩存文件是否存在
	            if(file_exists($_cacheFile) && file_exists($_parFile)){
	                //是否修改過編譯文件或者模板文件
	                if(filemtime($_cacheFile)>=filemtime($_parFile) && filemtime($_parFile)>filemtime($_tplFile)){
	                    echo '以下是緩存文件內容';
	                    echo "<br />";
	                    include $_cacheFile;
	                    return;
	                }
	            }
	        }
	        //判斷編譯文件是否存在,模板文件是否修改過
	        if(!file_exists($_parFile) || (filemtime($_parFile) < filemtime($_tplFile))){
	            
	            //引入模板解析類
	            require ROOT_PATH.'/includes/Parser.class.php';
	            //實例化對象,生成編譯文件
	            $_parser = new Parser($_tplFile);//模板文件
	            $_parser->compile($_parFile);//編譯後文件
	            
	        }

	        //載入編譯文件
	        include $_parFile;
	        if(IS_CACHE){
    	        //生成緩存文件
    	        file_put_contents($_cacheFile, ob_get_contents());
    	        //清除緩沖區
    	        ob_end_clean();
    	        //載入緩存文件
    	        include $_cacheFile;
	        }


	    }
	}

解析類:

//Parser.class.php
	class Parser {
	    //獲取模板內容
	    private $_tpl;
	    //構造方法,初始化模板
	    public function __construct($_tplFile){
	        //判斷文件是否存在
	        if(!$this->_tpl = file_get_contents($_tplFile)){
	            exit('ERROR:讀取模板出錯!');
	        }
	        
	    }
	    
	    //解析普通變量
	    private function parVar(){
    	    $_pattern = '/\{\$([\w]+)\}/';
    		if (preg_match($_pattern,$this->_tpl)) {
    			$this->_tpl = preg_replace($_pattern,"<?php echo \$this->_vars['$1'] ?>",$this->_tpl);
    		}
	    }
	    //解析IF條件語句
	    private function parIf(){
	        //開頭if模式
	        $_patternIf = '/\{if\s+\$([\w]+)\}/';
	        //結尾if模式
	        $_patternEnd = '/\{\/if\}/';
	        //else模式
	        $_patternElse = '/\{else\}/';
	        //判斷if是否存在
	        if(preg_match($_patternIf, $this->_tpl)){
	            //判斷是否有if結尾
	            if(preg_match($_patternEnd, $this->_tpl)){
	                //替換開頭IF
	                $this->_tpl = preg_replace($_patternIf, "<?php if(\$this->_vars['$1']){ ?>", $this->_tpl);
	                //替換結尾IF
	                $this->_tpl = preg_replace($_patternEnd, "<?php } ?>", $this->_tpl);
	                //判斷是否有else
	                if(preg_match($_patternElse, $this->_tpl)){
	                    //替換else
	                    $this->_tpl = preg_replace($_patternElse, "<?php }else{ ?>", $this->_tpl);
	                }
	            }else{
	                exit('ERROR:語句沒有關閉!');
	            }
	        }
	    }
	    //解析foreach
	    private function parForeach(){
	        $_patternForeach = '/\{foreach\s+\$(\w+)\((\w+),(\w+)\)\}/';
	        $_patternEndForeach = '/\{\/foreach\}/';
	        //foreach裡的值
	        $_patternVar = '/\{@(\w+)\}/';
	        //判斷是否存在
	        if(preg_match($_patternForeach, $this->_tpl)){
	            //判斷結束標志
	            if(preg_match($_patternEndForeach, $this->_tpl)){
	                //替換開頭
	                $this->_tpl = preg_replace($_patternForeach, "<?php foreach(\$this->_vars['$1'] as \$$2=>\$$3){?>", $this->_tpl);
	                //替換結束
	                $this->_tpl = preg_replace($_patternEndForeach, "<?php } ?>", $this->_tpl);
	                //替換值
	                $this->_tpl = preg_replace($_patternVar, "<?php echo \$$1?>", $this->_tpl);
	            }else{
	                exit('ERROR:Foreach語句沒有關閉');
	            }
	        }
	    }
	    //解析include
	    private function parInclude(){
	        $_pattern = '/\{include\s+\"(.*)\"\}/';
	        if(preg_match($_pattern, $this->_tpl,$_file)){
	            //判斷頭文件是否存在
	            if(!file_exists($_file[1]) || empty($_file[1])){
	                exit('ERROR:包含文件不存在!');
	            }
                //替換內容
                $this->_tpl = preg_replace($_pattern, "<?php include '$1';?>", $this->_tpl);
	        }
	    }
	    //解析系統變量
	    private function configVar(){
	        $_pattern = '/<!--\{(\w+)\}-->/';
	        if(preg_match($_pattern, $this->_tpl,$_file)){
 	            $this->_tpl = preg_replace($_pattern,"<?php echo \$this->_config['$1'] ?>", $this->_tpl);
                
	        }
	    }
	    
	    //解析單行PHP注釋
	    private function parCommon(){
	        $_pattern = '/\{#\}(.*)\{#\}/';
	        if(preg_match($_pattern, $this->_tpl)){
	            $this->_tpl = preg_replace($_pattern, "<?php /*($1) */?>", $this->_tpl);
	        }
	    }
	    
	    
	    //生成編譯文件
	    public function compile($_parFile){
	        //解析模板變量
	        $this->parVar();
	        //解析IF
	        $this->parIf();
	        //解析注釋
	        $this->parCommon();
	        //解析Foreach
	        $this->parForeach();
	        //解析include
	        $this->parInclude();
	        //解析系統變量
	        $this->configVar();
	        //生成編譯文件
	        if(!file_put_contents($_parFile, $this->_tpl)){
	            exit('ERROR:編譯文件生成失敗!');
	        }
	    }
	}

  

總結:模板引擎的整個過程:

  1、當浏覽器請求index.php文件時,實例化模板類對像 $_tpl = new Templates();

  2、當Templates實例化的時候,生成兩個數組,一個用來存放模板變量,另一個存放系統變量,通過構造方法,判斷文件夾是否存在,同時通過XML文件將系統變量數組初始化

  3、通過模板類Templates的注入方法,assign(),將對應模板index.tpl中變量的index.php的內容注入到模板類的私有變量,完成初始化

  4、模板類Templates類顯示方法display() 通過實例化解析類Parser,將取到的注入變量通過解析類進行解析(即替換)

  5、解析(替換)後,將文件寫入PHP、HTML混全文件

  6、通過Templates類的顯示方法將文件輸出:

     1、第一次執行顯示方法時,將會把PHP、HTML混合文件,生成純靜態的緩存文件

     2、調用緩存文件,顯示頁面

     3、當浏覽器再次調用顯示方法時,首先根據各文件的最後修改時間,判斷是否重新生成緩存文件或直接調用已存在的緩存文件

重點:

  1、通過正則表達式進行字符串的替換

  2、熟悉OOP

  

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved