自己写的php模板引擎 | ||||||||||||||||
一直在用smarty,总觉得它过于臃肿。所以自己写了一个。 在跟目录建index.php文件,内容 php header ( 'Content-Typetexthtml;charset=utf-8' ); 网站跟目录 define ( 'ROOT_PATH' , $_SERVER ['DOCUMENT_ROOT'].'zero' ); 存放模板文件夹 define('ZR_DIR' , ROOT_PATH.'templates'); 编译文件夹 define('ZR_C_DIR' , ROOT_PATH.'templates_c'); require ROOT_PATH.'classzero.class.php'; $ZR = new Zero(); $ZR-assign('name','潘泽学的模板'); $ZR-assign('if',true); $array = array('1'='1','2'='2'); $ZR-assign('array',$array); $ZR-debug('index.html'); $ZR-display('index.html'); 在跟目录建templates文件夹,再在templates文件夹内建 index.html文件,内容 <html> <head> <head> <body> {$name} {#}........{#} {if $if} div当$if等于true时会显示这句话div {if} foreach语句br {$array-foreach(key,value)} {@key}={@value}br {foreach} </body> </html> 在跟目录建templates_c文件夹,无内容但此文件夹要有写权限。 在跟目录建class文件夹。 在class文件夹内建zero.class.php文件,内容 php class Zero{ 保存模板变量 private $_zr_vars; 保存模板文件名 private $_zr_file; 保存ZoreParser对象(编译对象) private $_parser; 保存ZoreDebug对象(调试对象) private $_debugger; 构造函数 public function __construct(){ 判断模板文件夹和编译文件夹是否存在 if(!is_dir(ZR_DIR) !is_dir(ZR_C_DIR)){ exit('错误请正确设置模板文件夹和编译文件夹'); } } 设置模板变量 public function assign($var,$value){ 判断$var是否有值 if(isset($var) && trim($var) != ''){ $this-_zr_vars[$var] = $value; return true; } else { exit('错误请设置变量名'); } } 检测模板是否更新,更新则再编译,没有更新就用原来编译后的文件 public function display($zr_file){ $template_file = ZR_DIR.$zr_file; 判断模板文件是否存在 if(!file_exists($template_file)){ exit('错误模板文件不存在'); } $parsed_file = ZR_C_DIR.md5($zr_file).'.php'; if(!file_exists($parsed_file) filemtime($parsed_file) filemtime($template_file)){ if(TRUE){ require_once ROOT_PATH.'classzero_parser.class.php'; $this-_parser = new ZeroParser(); $this-_parser-compile($zr_file); } include $parsed_file; } public function debug($zr_file){ if(include_once(ROOT_PATH.'classzero_debugger.class.php')){ $this-_debugger = new ZeroDebuger($zr_file); $this-_debugger-start(); } else { exit('错误Debuger类文件不存在'); } } } 在class文件夹内建zero_debugger.class.php文件,内容 php class ZeroDebuger{ private $template; 用来保存模板的内容 private $IF_LINE_NUM; 用来保存IF所在的行数 private $ENDIF_LINE_NUM; 用来保存ENDIF所在的行数 private $FOREACH_LINE_NUM; 用来保存FOREACH所在的行数 private $ENDFOREACH_LINE_NUM; 用来保存ENDFOREACH所在的行数 private $ERRORS; 用来保存错误信息 构造函数 public function __construct($file_name = NULL){ if(isset($file_name) && trim($file_name) != ''){ $this-set_file($file_name); } } 打开模板文件并读取文件内容 public function set_file($file_name){ $file_name = ZR_DIR.$file_name; if(file_exists($file_name)){ $fp = fopen($file_name,'r') OR exit('错误不能打开模板文件 '); if(($fs = filesize($file_name)) 0) $this-template = fread($fp,$fs); fclose($fp); return true; } exit('错误模板文件不存在'); } function start($display = FALSE){ 判断是否有{#} (注释) if(strpos($this-template,'{#}') != false){ 判断是否有{#}......{#} if(!preg_match({#}[^({#})]{#} , $this-template)){ $this-ERRORS[] = '错误{#}没有关闭'; } } 把模板内容按换行来分割成数组 $this-template = explode(n , $this-template); 循行数组 $line_number =1; foreach($this-template as $line){ 匹配{if....语句,并保存行数到IF_LINE_NUM变量中 if(preg_match({sif , $line)){ $this-IF_LINE_NUM[] = $line_number; } 匹配{if}语句,并保存行数到ENDIF_LINE_NUM if(preg_match({sifs} , $line)){ $this-ENDIF_LINE_NUM[] = $line_number; } 匹配{$array_name-foreach(key, value)....语句,并保存行数 到FOREACH_LINF_NUM变量中 if(preg_match({s$[0-9a-zA-Z_]+-foreach(s[0-9a-zA-Z_]+s,s[0- 9a-zA-Z_]+s)s , $line)){ $this-FOREACH_LINE_NUM[] = $line_number; } 匹配{foreach}语句,并保存行数到ENDFOREACH变量中 if(preg_Match({sforeachs} , $line)){ $this-ENDFOREACH_LINE_NUM[] = $line_number; } 检测include语法是否正确(是否符合{include .......}) if(strpos($line , {include) != false){ if(!preg_match({include [^}]} , $line)){ $this-ERRORS[] = '错误INCLUDE语法使用错误,在行font color=red'.$line_number.'font'; } } $line_number++; } 调用if和foreach两个方法 $this-check_if(); $this-check_foreach(); if(count($this-ERRORS) 0){ echo 'div style=border1px solid #f60;padding10px;width500px;font-size12px;color#800;'; foreach($this-ERRORS as $e){ echo $e,'br'; } echo 'div'; } else { if($display) echo $this-highlight_html(implode('',$this-template)); echo 'div style=border1px solid #f60;padding10px;width200px;font-size12px;test-aligncenter; color#800;恭喜模板没有错误div'; } } 检测{if .......}.....{if}语句是否合理或是否关闭 private function check_if(){ $ifs = count($this-IF_LINE_NUM); for($i = 0; $i $ifs; $i++){ if(isset($this-ENDIF_LINE_NUM[$i])){ if($this-IF_LINE_NUM[$i] $this-ENDIF_LINE_NUM[$i]){ $this-ERRORS[] = '错误在没有IF的情况下使用END IF,在行 font color=red'.$this-IF_LINE_NUM[$i].'font'; } } else { $this-ERRORS[] = '错误IF没有关闭,在行font color=red'.$this-IF_LINE_NUM[$i].'font'; } if(count($this-IF_LINE_NUM) == 0 && count($this-ENDIF_LINE_NUM) 0){ foreach($this-ENDIF_LINE_NUM as $line_number){ $this-ERRORRS[] = '错误在没有IF的情况下使用END IF,在 行font color=red'.$line_number.'font'; } } } print_r($this-FOREACH_LINE_NUM); } 检测{$array_name-foreach(key, value)}....................{foreach}语句是否合理或是否关闭 private function check_foreach(){ $foreachs = count($this-FOREACH_LINE_NUM); for($i = 0 ; $i $foreachs ; $i++){ if(isset($this-ENDFOREACH_LINE_NUM[$i])){ if($this-FOREACH_LINE_NUM[$i] $this-ENDFOREACH_LINE_NUM[$i]){ $this-ERRORS[] = '错误在没有FOREACH的情况下使用END FOREACH,在行font color=red'.$this-ENDFOREACH_LINE_NUM[$i].'font'; } } else { $this-ERRORS[] = '错误FOREACH没有关闭,在行font color=red'.$this-FOREACH_LINE_NUM[$i].'font'; } } if(count($this-FOREACH_LINE_NUM) == 0 && count($this-ENDFOREACH_LINE_NUM) 0){ foreach($this-ENDFOREACH_LINE_NUM as $line_number){ $this-ERRORS[] = '错误在没有FOREACH的情况下使用END FOREACH,在行font color=red'.$line_number.'font'; } } } private function highlight_html($code){ $code = str_replace('','',$code); $code = str_replace('','',$code); $code = preg_replace('([a-zA-Z_]+)=','font color=#FF0000$1=font',$code); $code = preg_replace('([a-zA-Z0-9$;]+)','font color=#0000FF$1font',$code); $code = str_replace('!--','font color=#008080!--',$code); $code = str_replace('--','--font',$code); $code = n12br($code); return $code; } } 在class文件夹内建zero_parser.class.php文件,内容 php class ZeroParser{ 用来保存模板内容 private $template; 设置和读取模板 private function set_file($file){ 模板路径 $file = ZR_DIR.$file; if(!file_exists($file)){ exit('错误模板文件不存在'); } 打开模板文件 $fp = fopen($file,'r'); if(!$fp) exit('错误不能打开文件'); if(filesize($file)){ 读取模板文件的内容 $this-template = fread($fp,filesize($file)); } else { exit('错误模板文件大小为零'); } 关闭打开的文件 fclose($fp); return true; } 解析变量 private function _parse_var(){ 变量匹配正则 $patten = '{$([a-zA-Z0-9]+)}'; if(strpos($this-template,'{$') !== false){ 正则替换 $this-template = preg_replace($patten,php echo $this-_zr_vars['$1']; ,$this-template); } return true; } 解析IF条件语句 private function _parse_if(){ 判断模板文件中是否有IF语句 if(preg_match({sif,$this-template)){ if(preg_match('{sifs}',$this-template)){ $if_patten = {sifs+$([a-zA-Z0-9]+)}; $ef_patten = {sifs}; $this-template = preg_replace($if_patten,php if($this-_zr_vars['$1']){,$this-template); $this-template = preg_replace($ef_patten,php }; ,$this-template); } else { exit('错误语法错误,没有封闭IF条件语句'); } } return true; } 解析注释语句 private function _parse_common(){ $patten = {#}([^{]){#}; if(strpos($this-template,'{#}') !== false){ $this-template = preg_replace($patten,php $1 ,$this-template); } return true; } include语句 private function _parse_include(){ if(preg_match({sinclude ([^}])s},$this-template,$file)){ if(trim($file[1]) == '') exit('错误文件指定包含的文件'); if(!file_exists(trim($file[1]))) exit('错误文件不存在'); $include_patten = '{sinclude ([^]+)S}'; $include_patten = preg_replace($include_patten,php include '$1'; ,$this-template); } return true; } 解析Foreach语句 private function _parse_foreach(){echo 'aa'; if(preg_match({s$[0-9a-zA-Z_]+-foreach(s[0-9a-zA-Z_]+s,s[0-9a-zA-Z_]+s)s , $this-template)){ echo 'dd'; if(preg_match({sforeachs},$this-template)){ 循环内的变量 如{@key} if(preg_match({s@[0-9a-zA-Z_],$this-template)){ $k_and_v_patten = {s@([0-9a-zA-Z_]+)s}; $this-template = preg_replace($k_and_v_patten,php echo $$1; , $this-template); } $foreach_patten = {s$([0-9a-zA-Z_]+)s-sforeach(s([0-9a-zA-Z_]+)s,s([0-9a-zA-Z_]+)s)s}; $end_foreach_patten = {sforeachs}; $this-template = preg_replace($foreach_patten,php foreach($this-_zr_vars['$1'] as $$2 = $$3){ ,$this-template); $this-template = preg_replace($end_foreach_patten,php }; ,$this-template); } else { exit('错误语法错误,没有封闭FOREACH条件语句'); } } } compile方法 public function compile($file_name){ $this-set_file($file_name); 读取模板文件 $this-_parse_var(); $this-_parse_if(); 解析if语句 $this-_parse_common(); 解析注释语句 $this-_parse_foreach(); 解析foreach()语句 $this-_parse_include(); 解析include()语句 $zr_c_file = ZR_C_DIR.md5(basename($file_name)).'.php'; 产 生缟译后的文件名 $fp = fopen($zr_c_file,'w'); fwrite($fp,$this-template); fclose($fp); } } 在是和smarty一样要编译后才可运行的模板引擎,下面在说个不用编译的,这总方法就有点像cake自带的模板引擎。不说这什么多了,先看看代码吧。 建个index.php文件,内容 php 检查zero类是否已定义 if(!class_exists('zero')){ require 'zero.php'; } class controller{ private $zero = NULL; public function __construct(){ $this-zero = new zero(); 告诉模板引擎加载哪个模板 $this-zero-load('index.html'); } public function index(){ $parameter = '我是由模板引擎传过来的!'; $this-zero-set('parameter',$parameter); $this-zero-set('arr',array(1,2,3,4,5,6,7)); } } $cont = new controller(); $cont-index(); 建个zero.php文件,内容 php 模板引擎 class zero{ 模板 private $templet = NULL; 变量数组 private $variable = array(); public function __construct(){ } public function load($path){ $this-templet = $path; } public function set($key,$value){ $this-variable = array_merge($this-variable,array( $key=$value )); } function __destruct(){ extract($this-variable,EXTR_PREFIX_SAME,'zero'); require dirname ( __FILE__ ).'Temp'.$this-templet; } } 这就完事了,要是有什么不会的可以给我留言。
|