分享

PHP 实现简单的模板引擎

 quasiceo 2017-02-16
PHP 实现简单的模板引擎

摘要: 实现M(Moudle)和V(view)层的代码分离

模板引擎作为视图层和模型曾分离的一种解决方案。

首先我们新建一个Template.class.php 的文件

<?php
class 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

<?php
include "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核心技术与最佳实践

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多