最新消息:

教你如何写一个自己的PHP模板引擎

gtocms eben 575浏览

PHP模板引擎就是一个PHP类库,使用它可以使PHP代码和HTML代码进行分离,使代码的可读性和维护性得到显著提高。而且这样做的好处是,让美工专心设计HTML前台页面,程序员专心去写PHP业务逻辑。因此,模化引擎很适合公司的Web开发团队使用,使每个人都能发挥其特长。
目前,可以在PHP中应用的并且比较成熟的模板引擎有很多,例如Smarty、TinyButStrong、Template Lite、XTemplate等几十种。使用这些通过PHP编写的模板引擎,可以让你的代码脉络更加清晰,结构更加合理化。也可以让网站的维护和更新变得更容易,创造一个更加良好的开发环境,让开发和设计工作更容易结合在一起。
废话就说到这里,下面教大家如何写这个模板引擎。
首先看一下整个文件夹的目录结构:

教你如何写一个自己的PHP模板引擎-1

tpl文件:模板文件根目录
cache:缓存文件夹
config:系统配置文件夹
includes:引擎核心类库文件夹
templates:模板文件夹
templates_c:编译文件夹
index.php:测试文件
template.inc.php:初始化配置文件

index.php测试文件:
<?php
require ‘template.inc.php’;//载入初始化配置文件

$tpl=new Templates();//实例化模板类

$tpl->assign(‘content’,’打造自己的PHP模板引擎!’);//分配变量
$tpl->assign(‘bool’,true);
$tpl->assign(‘colors’,array(‘red’,’green’,’blue’));

$tpl->display(‘index.tpl’);//显示模板文件
?>

template.inc.php初始化配置文件
<?php
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’,false);//是否开启缓存
//自动载入类的方法
function __autoload($className){
require_once ROOT_PATH.’/includes/’.$className.’.class.php’;
}
?>

接下来就是模板引擎核心类文件:
Templates.class.php模板类文件
<?php
//模板类
class Templates {
private $_vars=array();//存放模板引擎注入的普通变量
private $_configs=array();//载入的系统变量
private $tpl_file;//模板文件路径
private $parse_file;//编译文件路径
private $cache_file;//缓存文件路径
//模板构造方法,主要完成相关目录是否存在的检测,以及将系统变量的值读入到$_configs变量中
public function __construct(){
$this->is_dir_exists();
$this->getConfig();
}
//display()方法:完成与编译,缓存相关的一些功能
public function display($file){
$this->tpl_file=TPL_DIR.$file;//设置模板文件路径
if(!file_exists($this->tpl_file)){
exit($file.’模板文件不存在!’);
}
$this->parse_file=TPL_C_DIR.md5($file).’.’.$file.’.php’;//设置编译文件路径
include ROOT_PATH.’/includes/Parse.class.php’;//载入模板解析类
$parse=new Parse($this->tpl_file);//初始化模板解析类
$parse->compile($this->parse_file,$this->tpl_file);//解析静态模板文件,生成编译文件

//判断是否需要重新生成缓存文件
$this->cache();
}
//assign()方法:接收从index.php文件分配过来的变量的值,将它们保存在$_vars变量中

 

public function assign($var,$value){
if(isset($var)&&!empty($var)){//判断模板变量是否有设置,且不能为空
$this->_vars[$var]=$value;//接收从index.php文件分配过来的变量的值,将它们保存在$_vars变量中
}else{
exit(‘请设置模板变量!’);
}

}
//getConfig()方法:将系统变量的值读入到$_configs变量中
private function getConfig(){
if(file_exists(ROOT_PATH.’/config/profile.xml’)){//判断系统配置文件是否存在
$sxe=simplexml_load_file(ROOT_PATH.’/config/profile.xml’);//载入系统配置文件
$taglib=$sxe->xpath(‘/root/taglib’);//使用xpath()方法读取相关节点
foreach($taglib as $value){
$this->_configs[“$value->name”]=$value->value;//将系统变量的值读入到$_configs变量中
}
}
}
//is_dir_exists()方法:相关目录是否存在的检测
private function is_dir_exists(){
if(!is_dir(TPL_DIR)){//检测是否存在模板文件夹
exit(‘模板文件夹不存在!’);
}
if(!is_dir(TPL_C_DIR)){//检测是否存在编译文件夹
exit(‘编译文件夹不存在!’);
}
if(!is_dir(CACHE_DIR)){//检测是否存在缓存文件夹
exit(‘缓存文件夹不存在!’);
}
}
//cache()方法:完成与缓存相关的一些功能
private function cache(){
$this->cache_file=CACHE_DIR.md5($file).’.’.$file.’.html’;//设置缓存文件路径
//如果开启缓存,缓存文件存在且模板文件没有被修改过,直接载入缓存文件
if(IS_CACHE){
if(file_exists($this->cache_file)&&filemtime($this->cache_file)>=filemtime($this->parse_file)){
include $this->cache_file;//载入缓存文件
return ;
}
}
//判断是否开启缓存,如果开启就生成静态html文件,否则,直接载入编译文件
IS_CACHE? ob_start():null;
if(IS_CACHE){
include $this->parse_file;
file_put_contents($this->cache_file,ob_get_contents());//生成静态html缓存文件
ob_end_clean();
include $this->cache_file;//载入静态html缓存文件
}else{
include $this->parse_file;//载入编译文件
}
}
}
?>

Parse.class.php模板解析类文件
<?php
//模板解析类
class Parse {
private $_tpl;//存放静态模板文件的内容
//初始化构造方法:读取模板文件内容保存到到$_tpl变量中
public function __construct($tpl_file){
if(!$this->_tpl=file_get_contents($tpl_file)){//读取静态模板文件内容到$_tpl变量中
exit(‘模板内容读取失败!’);
}
}
//compile()方法:完成静态模板的解析并生成编译文件
public function compile($parse_file,$tpl_file){
$this->parse();//调用私有方法parse()完成各种标签的解析
//如果编译文件不存在或是模板文件被修改过就生成编译文件
if(!file_exists($parse_file)||filemtime($tpl_file)>=filemtime($parse_file)){
if(!file_put_contents($parse_file,$this->_tpl)){
exit(‘编译文件生成失败!’);
}
}
}
//parseVar()方法:解析普通变量
private function parseVar(){
$mode=’/\{\$([\w]+)\}/’;//普通变量模式
//在模板文件中匹配模式,如果匹配成功,则替换成index.php文件中注入的变量
if(preg_match($mode,$this->_tpl)){
$this->_tpl=preg_replace($mode,”<?php echo \$this->_vars[‘$1’];?>”,$this->_tpl);//替换成index.php文件中注入的变量
}
}
//parseIf()方法:解析if语句
private function parseIf(){

 

//if语句模式
$modeIf=’/\{if\s+\$([\w]+)\}/’;
$modeEndIf=’/\{\/if\}/’;
$modeElse=’/\{else\}/’;
//在模板文件中匹配模式,如果匹配成功,则替换成相应的php语言中的if语句
if(preg_match($modeIf,$this->_tpl)){
if(preg_match($modeEndIf,$this->_tpl)){
$this->_tpl=preg_replace($modeIf,”<?php if(\$this->_vars[‘$1’]){?>”,$this->_tpl);
$this->_tpl=preg_replace($modeEndIf,”<?php }?>”,$this->_tpl);
if(preg_match($modeElse,$this->_tpl)){
$this->_tpl=preg_replace($modeElse,”<?php }else{?>”,$this->_tpl);
}
}else{
exit(‘If语句没有关闭!’);
}
}
}
//parseInclude()方法:解析普通文件包含标签
private function parseInclude (){
$mode=’/\{include\s+file=\”(.+)\”\}/’;//普通文件包含标签模式
//在模板文件中匹配模式,如果匹配成功,则替换成相应的php语言中的include包含语句
if(preg_match($mode,$this->_tpl,$file)){
if(!file_exists(TPL_DIR.$file[1])){
exit(‘包含文件出错!’);
}
$this->_tpl=preg_replace($mode,”<?php include TPL_DIR.’$1′;?>”,$this->_tpl);//替换成相应的php语言中的include包含语句
}
}
//parseCommon()方法:解析注释标签
private function parseCommon(){
$mode=’/{#\s+(.*)\s+#}/’;//注释标签模式
//在模板文件中匹配模式,如果匹配成功,则替换成相应的php语言中的注释
if(preg_match($mode,$this->_tpl)){
$this->_tpl=preg_replace($mode,”<?php /* ‘$1′ */?>”,$this->_tpl);//替换成相应的php语言中的注释
}
}
//parseConfig()方法:解析系统变量
private function parseConfig(){
$mode=’/\{\$config\.([\w]+)\}/’;//系统变量匹配模式
//在模板文件中匹配模式,如果匹配成功,则替换成读入的系统变量的值
if(preg_match($mode,$this->_tpl)){
$this->_tpl=preg_replace($mode,”<?php echo \$this->_configs[‘$1′];?>”,$this->_tpl);//替换成读入的系统变量的值
}
}
//parse()方法:内部调用各种解析方法
private function parse(){
$this->parseInclude();
$this->parseConfig();
$this->parseCommon();
$this->parseForeach();
$this->parseVar();
$this->parseIf();
}
//parseForeach()方法:解析foreach语句
private function parseForeach(){
//foreach语句匹配模式
$modeForeach=’/\{foreach\s+key=([\w]+)\s+item=([\w]+)\s+from=\$([\w]+)\}/’;
$modeEndForeach=’/\{\/foreach\}/’;
$modeVar=’/\{@([\w]+)\}/’;
//在模板文件中匹配模式,如果匹配成功,则替换成相应的php语言中的foreach语句
if(preg_match($modeForeach,$this->_tpl)){
if(preg_match($modeEndForeach,$this->_tpl)){
$this->_tpl=preg_replace($modeForeach,”<?php foreach(\$this->_vars[‘$3’] as \$$1=>\$$2){?>”,$this->_tpl);
$this->_tpl=preg_replace($modeVar,”<?php echo \$$1;?>”,$this->_tpl);
$this->_tpl=preg_replace($modeEndForeach,”<?php }?>”,$this->_tpl);
}else{
exit(‘Foreach语句没有关闭!’);
}
}
}
}
?>

index.tpl静态模板测试文件
<!DOCTYPE html PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN” “http://www.w3.org/TR/html4/loose.dtd“>
<html>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=UTF-8″>
<title>{$config.webname}</title>
</head>
<body>
{include file=”header.tpl”}
{# 这里是注释内容! #}
{$content}<br/>
{if $bool}
bool是真<br/>
{else}
bool是假<br/>
{/if}
{foreach key=key item=item from=$colors}
{@key}–{@item}<br/>
{/foreach}
{include file=”footer.tpl”}

<div id=”footer”>
<p>Powered by {$config.author} (C) 2012-2013 DesDev Inc.</p>
<p>Copyright (C) 2012-2013 YunQueZhai.</p>
</div>

</body>
</html>

profile.xml系统配置文件
<?xml version=”1.0″ encoding=”utf-8″?>
<root>
<taglib>
<name>webname</name>
<value>用自己写的PHP模板引擎构建CMS系统</value>
</taglib>
<taglib>
<name>author</name>
<value>风影园居</value>
</taglib>
</root>

测试效果:

教你如何写一个自己的PHP模板引擎-2

转载请注明:落伍老站长 » 教你如何写一个自己的PHP模板引擎