主页
软件技术
返回
自己写的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;

}

}

这就完事了,要是有什么不会的可以给我留言。



一级建造师《建筑工程》考试复习要点:合同管理
一级建造师《项目管理》复习要点:施工质量控制和验收
易介中:建筑师的大是大非
加强基础设施建设时期的工程项目管理
牛长春:历史文化建筑的保护规划关乎一座城市的未来
09年一级建造师考试《法规及相关知识》辅导资料(133)
赵彬:如何在雾霾天保护自己和家人
工程项目管理的三控制
信息发布:名易软件http://www.myidp.net