现在的位置: 首页 > php学习 > 正文

自己编写php类似smarty模板引擎

2014年10月04日 php学习 ⁄ 共 7097字 ⁄ 字号 暂无评论 ⁄ 阅读 1,522 次

自己编写php类似smarty模板引擎,自己写的网站进度在smarty模板引擎,好处就是前台和后台的分离,缓存文件的引用.以下是网上的很不错的代码段.

tpl文件:模板文件根目录

cache:缓存文件夹

config:系统配置文件夹

includes:引擎核心类库文件夹

templates:模板文件夹

templates_c:编译文件夹

index.php:测试文件

template.inc.php:初始化配置文件

1

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>

测试效果:

2

ps:   问:那如果是二维数组怎么解析呢?

答 : 把Parse.class.php模板解析类文件中的 $modeVar='/\{@([\w]+)\}/'; 扩展一下改为$modeVar='/\{@(\w+\[?\w*\]?)\}/';这样,那么 foreach 中便可使用{@item[0]}这样的格式了

包含parseInclude 这个方法是有问题的吧!这样的包含文件的标签不能被解析呀.改一下:(参考未测试)

if (preg_match ( $mode, $this->_tpl, $file )) {
$include_file=nulll;
if (! file_exists ( TPL_DIR . $file [1] )) {
exit ( '包含文件出错!' );
}else{
$include_file=file_get_contents(TPL_DIR . $file [1]);
}
//加载包含文件的内容
$this->_tpl = preg_replace ( $mode,$include_file, $this->_tpl ); //替换成相应的php语言中的include包含语句
}

猜你喜欢

给我留言

留言无头像?