Maison >développement back-end >tutoriel php >PHP 实现简单的模板引擎
模板引擎作为视图层和模型曾分离的一种解决方案。
首先我们新建一个Template.class.php 的文件
<?phpclass Template{ private $arrayConfig = array( 'suffix' => '.m', //设置模板文件 'templateDir' => 'template/', //设置模板所在的文件夹 'compileDir' => 'cache', 'debug' => false, //设置编译后存放的目录 'cache_htm' => true, //是否需要编译成静态的html文件 'suffix_cache'=> '.htm', //编译后的文件后缀 'cache_time' =>2000, // 多长时间自动更新 'php_turn' =>false, //是否支持原生的php代码 'cache_control' => 'control.dat', ); private $compileTool; //编译器 public $filename; //模板文件名称 private $value =array(); //值栈 static private $instance = null; public $debug = array(); //调试信息 public function __construct($arrayConfig =array()){ //返回当前UNIX时间戳和微妙数 $this->debug['begin'] = microtime(true); $this->arrayConfig =$arrayConfig+$this->arrayConfig; $this->getPath(); if(!is_dir($this->arrayConfig['templateDir'])){ exit("template isnt not found"); } if(!is_dir($this->arrayConfig['compileDir'])){ mkdir($this->arrayConfig['compileDir'],0770,true); } include("Compile.class.php"); //$this->compileTool = new Compile; } /** 路径处理为绝对路径 */ public function getPath(){ $this->arrayConfig['templateDir'] = strtr(realpath($this->arrayConfig['templateDir']),'\\','/').'/'; $this->arrayConfig['compileDir'] = strtr(realpath($this->arrayConfig['compileDir']),'\\','/').'/'; } /*** 单例模式获取模板的实例 **/ public static function getInstance(){ if(is_null(self::$instance)){ self::$instance = new Template(); } return self::$instance; } public function setConfig($key,$value = null){ if(is_array($key)){ $this->arrayConfig = $key+$this->arrayConfig; }else{ $this->arrayConfig[$key] = $value; } } public function getConfig($key = null){ if($key){ return $this->arrayConfig[$key]; }else{ return $this->arrayConfig; } } /** 注入单个变量 **/ public function assign($key,$value){ $this->value[$key] = $value; } /** 注入多个变量 **/ public function assignArray($array){ if(is_array($array)){ foreach($array as $k => $v){ $this->value[$k] = $v; } } } /*** 获取模板文件的路径 **/ public function path(){ return $this->arrayConfig['templateDir'].$this->filename.$this->arrayConfig['suffix']; } /*** 是否需要缓存 **/ public function needCache(){ return $this->arrayConfig['cache_htm']; } /*** 是否需要重新生成缓存文件 **/ public function reCache($file){ $flag = false; //生成缓存文件 $cacheFile = $this->arrayConfig['compileDir'].md5(@$filename).'.'.'php'; //var_dump($cacheFile); if($this->arrayConfig['cache_htm']===true){ //设置timeflag (判断当前时间-模板文件上次修改的时间)是否小于设置的缓存时间 //如果小于则返回TRUE $timeFlag = (time()-@filemtime($cacheFile))<$this->arrayConfig['cache_time']? true:false; //1,判断缓存文件是否存在, //2,缓存文件是否有内容 //3,时间是否在设置的缓存时间之内 if(!is_file($cacheFile)&&filesize($cacheFile)>1&&$timeFlag){ $flag = true; }else{ $flag = false; } } return $flag; } /*** 显示模板 **/ public function show($file){ $this->filename =$file; if(!is_file($this->path())){ exit('找不到相对应的模板'); } $compileFile = $this->arrayConfig['compileDir'].'/'.md5(@$filename).'.php'; $cacheFile = $this->arrayConfig['compileDir'].md5(@$filename).'.htm'; // echo $compileFile; //echo $cacheFile; if($this->reCache($file)===false){ $this->debug['cached'] = 'false'; // var_dump($compileFile); $this->compileTool = new Compile($this->path(),$compileFile,$this->arrayConfig); if($this->needCache()){ //是否需要缓存 ob_start(); } //函数从数组中把变量导入到当前的符号表中 extract($this->value,EXTR_OVERWRITE); //判断 文件是否存在,生成文件的修改时间是否小于模板文件修改时间 if(@is_file($compileFile)||filemtime($compileFile)<filemtime($this->path())){ $this->compileTool->vars = $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; } $this->debug['spend'] = microtime(true) - $this->debug['begin']; $this->debug['count'] = count($this->value); $this->debug_info(); /* var_dump($compileFile);this var_dump($this->path()); if(!is_file($compileFile)){ mkdir($this->arrayConfig['compileDir']); // 此处若存在需要判断 $this->compileTool->compile($this->path(),$compileFile); readfile($compileFile); }else{ readfile($compileFile); } */ } /*** debug 调试函数 **/ public function debug_info(){ //$this->arrayConfig['debug']=false; if($this->arrayConfig['debug']===true){ var_dump($this); echo "程序运行日期",date("Y-m-d h:i:s")."</br>"; echo "模板解析耗时",$this->debug['spend'],'秒'."</br>"; echo "模板包含标签数目",$this->debug['count']."</br>"; echo "是否使用静态缓存",$this->debug['cached']."</br>"; //echo "模板引擎实例参数",var_dump($this->getConfig()); } } /****** 清楚缓存的文件 *****/ public function clean($path = null){ if($path = null){ $path = $this->arrayConfig['CompileDir']; $path = glob($path.'*'.$this->arrayConfig['suffix_cache']); //glob 函数返回匹配指定的文件夹目录 }else{ $path = $this->arrayConfig['compileDir'].md5($path).'.htm'; foreach((array)$path as $v){ //删除 unlink($v); } } } }
新建一个 Compile.class.php 翻译模板文件
<?php class Compile{ private $template; //待编译的文件 private $content; //需要替换的文本 private $comfile; //编译后的 文件 private $left = '{'; private $right = '}'; private $value =array(); // 值栈 private $phpTurn; private $T_P = array(); private $T_R = array(); public function __construct($template,$compileFile,$config){ //echo $template; //echo $compileFile; $this->template = $template; $this->comfile = $compileFile; $this->content = file_get_contents($template); if($config['php_turn']===false){ //echo "123"; //$this->T_R[]=""; } //echo "123"; //正则匹配 {$xxx} 格式 $this->T_P[]="#\{\\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}#"; $this->T_R[]="<?php echo \$this->value['\\1'];?>"; } public function compile(){ $this->c_var2(); //$this->c_staticFile(); //var_dump($this); file_put_contents($this->comfile,$this->content); } public function c_var2(){ // 将{$xxx} 替换为<?php echo $xxx?> $this->content = preg_replace($this->T_P,$this->T_R,$this->content); } 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; } }
新建一个测试文件 test.php
<?phpinclude "Template.class.php";$tpl = Template::getInstance();//$tpl = new Template(array('php_turn'=>false,'debug'=>false));$tpl->assign('data','hello world');$tpl->show('member');//var_dump($tpl->getConfig());
模板文件member.m
<html><head></head><body><h1>welcome</h1></body>{$data}</html>
显示截图
借鉴 php核心技术与最佳实践