PHP模板解析入门
2017-07-14 09:13
225 查看
学习:李炎恢PHP视频第二季
模板引擎的特点:
1.鼓励分离:让更个系统的可读性和维护性得到提高。
2.促进分工:使得程序员和美工去专心处理自己的设计。
3.比PHP更容易解析:编译文件和缓存文件加载更快、占资源更少。
4.增加安全性:可限制模板设计师进行不安全的操作的能力避免误删误访问等
一个PHP对应一个模板文件,经过调用模板类并且经过模板解析类之后,生成编译过后的php编译文件,为了加快访问速度,并且生成纯静态的HTML文件,作为缓存文件。
简易目录:
1.cache文件夹存放静态HTML文件,加快访问速度
2.config文件夹存放系统变量的XML文件
3.includes 存放模板解析类库
-------------Parser.class.php 模板文件解析类 用于解析tpl文件,将其解析成php文件
------------Templates.class.php 模板类 负责提供给index.php调用传递数据和调用模板文件
4.templates文件夹 存放tpl文件
5.Templates文件夹 存放解析过后的tpl文件,为PHP文件
6.Index.php 调用入口文件
7.template.inc.php 初始化模板文件
8.Test.php 测试文件类
一、定义初始化变量
template.inc.php
<?php//设置utf-8编码
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',ROOT_PATH.'/cache/');
//是否开启缓冲区
define('IS_CACHE',true);
//开启缓冲区
IS_CACHE&&ob_start();
//引入模板类
require ROOT_PATH.'/includes/Templates.class.php';
//实例化模板类
$_tpl = new Templates();
二.入口文件index.php
引入初始化文件
require dirname(__FILE__).'/template.inc.php';
global $_tpl;
//声明一个变量
$_name = '周起';
$_array = array(1,2,3,4,5,6,7);
//调用方法注入变量给模板
$_tpl->assign('name',$_name);
$_tpl->assign('content','学习PHP');
$_tpl->assign('a',1);
$_tpl->assign('array',$_array);
//载入tpl文件
$_tpl->display('index.tpl');
三、Templates.class.php
<?phpclass Templates{
//字段用于接收动态变量
private $_vars = array();
//保存系统变量
private $_config = array();
//创建构造方法验证各个目录是否存在
public function __construct()
{
if (!is_dir(TPL_DIR)||!is_dir(TPL_C_DIR)||!is_dir(CACHE)){
exit('ERROR:模板目录或编译目录或缓存目录不存在,请手动添加');
}
//解析xml系统变量
$_sxe = simplexml_load_file('config/profile.xml');
$_taglib = $_sxe->xpath('/root/taglib');
foreach ($_taglib as $tag){
$this->_config["$tag->name"] = $tag->value;
}
}
//用于注入变量
/**
* @param $_var模板变量名
* @param $_value模板变量值
*/
public function assign($_var,$_value)
{
if (isset($_var)||!empty($_var)
){
$this->_vars[$_var] = $_value;
}else{
exit('ERROR:请设置模板变量');
}
}
//display() 生成编译文件和缓存文件
/**
* @param $_file模板文件路径
*/
public function display($_file)
{
//设置模板路径
$_tplFile = TPL_DIR.$_file;
//判断模板文件是否存在
if (!file_exists($_tplFile)){
exit('ERROR:'.$_file.'文件不存在');
}
//生成编译文件路径
$_parFile = TPL_C_DIR.md5($_file).$_file.'.php';
//生成缓存文件
$_cacheFile = CACHE.md5($_file).$_file.'.html';
//当第二次相同文件的时候,直接载入缓存文件,避开编译
if (IS_CACHE){
//缓存文件和编译文件同时存在
if (file_exists($_cacheFile)&&file_exists($_parFile)){
//并且模板文件修改时间大于编译文件
if (filemtime($_cacheFile)>=filemtime($_parFile)&&filemtime($_parFile)>=filemtime($_tplFile)){
//直接载入静态文件
include $_cacheFile;
return ;
}
}
}
//当编译文件不存在或者模板文件被修改的时候 重新生成编译文件
if (!file_exists($_parFile ||filemtime($_parFile)<filemtime($_tplFile))){
//引入模板解析类
require ROOT_PATH.'/includes/Parser.class.php';
//实例化对象的时候将模板文件路径传递进去
$_parser = new Parser($_tplFile);
$_parser->compile($_parFile);
}
//载入编译文件
include $_parFile;
if (IS_CACHE){
//获取缓冲区数据放入缓存文件
file_put_contents($_cacheFile,ob_get_contents());
//清除缓冲区
ob_end_clean();
//载入缓存文件
include $_cacheFile;
}
}
}
当实例化Template对象的时候,会先判断各个目录是否存在
当index.php调用$_tpl->assign()方法的时候,调用Template对象中的assign方法,在Template中有一个私有属性$_var为数组类,用于存放assign中的参数
//用于注入变量
/**
* @param $_var模板变量名
* @param $_value模板变量值
*/
public function assign($_var,$_value)
{
if (isset($_var)||!empty($_var)
){
$this->_vars[$_var] = $_value;
}else{
exit('ERROR:请设置模板变量');
}
}
如果变量不存在,或者变量为空的话,提示设置模板变量,否则,以变量名为数组索引,变量值为相对索引的值,存放入$_var私有变量中。
如果出现相同变量名就会出现因为索引相同,出现覆盖的情况。
//声明一个变量
$_name = '周起';
//调用方法注入变量给模板
$_tpl->assign('name',$_name);
$_tpl->assign('content','学习PHP');
$_tpl->assign('content','不想成为码农');
die();
这个时候掉用assign()方法,assign()方法改写为
public function assign($_var,$_value)
{
if (isset($_var)||!empty($_var)){
$this->_vars[$_var] = $_value;
}else{
exit('ERROR:请设置模板变量');
}
print_r($this->_vars);
}
在网页端打开访问
当调用Template类中display()方法的时候,传递进来一个模板文件名称
$_tpl->display(‘index.tpl’);
/**
* @param $_file模板文件路径
*/
public function display($_file)
{
//设置模板路径
$_tplFile = TPL_DIR.$_file;
//判断模板文件是否存在
if (!file_exists($_tplFile)){
exit('ERROR:'.$_file.'文件不存在');
}
//生成编译文件路径
$_parFile = TPL_C_DIR.md5($_file).$_file.'.php';
//生成缓存文件
$_cacheFile = CACHE.md5($_file).$_file.'.html';
//当第二次相同文件的时候,直接载入缓存文件,避开编译
if (IS_CACHE){
//缓存文件和编译文件同时存在
if (file_exists($_cacheFile)&&file_exists($_parFile)){
//并且模板文件修改时间大于编译文件
if (filemtime($_cacheFile)>=filemtime($_parFile)&&filemtime($_parFile)>=filemtime($_tplFile)){
//直接载入静态文件
include $_cacheFile;
return ;
}
}
}
//当编译文件不存在或者模板文件被修改的时候 重新生成编译文件
if (!file_exists($_parFile ||filemtime($_parFile)<filemtime($_tplFile))){
//引入模板解析类
require ROOT_PATH.'/includes/Parser.class.php';
//实例化对象的时候将模板文件路径传递进去
$_parser = new Parser($_tplFile);
$_parser->compile($_parFile);
}
//载入编译文件
include $_parFile;
if (IS_CACHE){
//获取缓冲区数据放入缓存文件
file_put_contents($_cacheFile,ob_get_contents());
//清除缓冲区
ob_end_clean();
//载入缓存文件
include $_cacheFile;
}
}
1.接收到tpl模板名称,定位到该模板文件路径,并且检测模板文件是否存在。
2.并且同时声明两个变量用于存放模板编译文件路径和纯静态HTML缓存文件路径
3.模板文件和编译文件和静态文件规则是这样:
如果编译文件和缓存文件都不存在,直接载入编译文件,并且生成静态缓存文件
当编译文件不存在或者模板文件被修改的时候,重新生成编译文件,并且生成静态缓存文件
当第二次访问相同页面,并且编译文件和缓存文件同时存在,并且缓存文件的修改时间大于编译文件的时候,直接访问静态缓存文件
知识点:file_put_contents() 函数把一个字符串写入文件中。
缓存机制:http://www.cnblogs.com/usa007lhy/p/5421545.html(推荐)
filemtime() 函数返回文件内容上次的修改时间。
fileatime() 函数返回指定文件的上次访问时间。
当第一次或者模板文件发生改变的时候,重新解析模板文件,并且将其解析
//当编译文件不存在或者模板文件被修改的时候 重新生成编译文件
if (!file_exists($_parFile ||filemtime($_parFile)<filemtime($_tplFile))){
//引入模板解析类
require ROOT_PATH.'/includes/Parser.class.php';
//实例化对象的时候将模板文件路径传递进去
$_parser = new Parser($_tplFile);
$_parser->compile($_parFile);
}
<?phpclass Parser{
//保存模板内容
private $_tpl;
//接收模板文件路径
public function __construct($_tplFile)
{
if (!$this->_tpl = file_get_contents($_tplFile)){
exit('ERROR:模板文件读取错误');
}
}
public function compile($_parFile)
{
$this->parConfig();
$this->parInclude();
$this->parForeach();
$this->parCommon();
$this->parIf();
$this->parVar();
//生成编译文件之前解析模板内容
if (!file_put_contents($_parFile,$this->_tpl)){
exit('ERROR:编译文件生成出错');
}
}
//解析if语句
private function parIf(){
$_pattenIf = '/\{if\s+\$([\w]+)\}/';
$_pattenEndIf = '/\{\/if\}/';
$_pattenElse = '/\{else\}/';
if (preg_match($_pattenIf,$this->_tpl)){
if (preg_match($_pattenEndIf,$this->_tpl)){
//匹配if开头
$this->_tpl = preg_replace($_pattenIf,'<?php if($this->_vars[\'$1\']){?>',$this->_tpl);
//匹配if结尾符并且更改为php形式
$this->_tpl = preg_replace($_pattenEndIf,"<?php };?>",$this->_tpl);
//匹配else
if (preg_match($_pattenElse,$this->_tpl)){
$this->_tpl = preg_replace($_pattenElse,"<?php }else{;?>",$this->_tpl);
}
}else{
exit('ERROR:IF语句没有关闭');
}
}
}
//解析PHP代码注释
private function parCommon(){
$_pattern = '/\{#\}(.*)\{#\}/';
if (preg_match($_pattern,$this->_tpl)){
$this->_tpl = preg_replace($_pattern,'<?php /*$1*/;?>',$this->_tpl);
}
}
//解析普通变量
private function parVar(){
$_pattern = '/\{\$([\w]+)\}/';
if (preg_match($_pattern,$this->_tpl)){
$this->_tpl = preg_replace($_pattern,"<?php echo \$this->_vars['$1'];?>",$this->_tpl);
}
}
//解析foreach语句
private function parForeach(){
$_patternForeach = '/\{foreach\s+\$([\w]+)\(([\w]+),([\w]+)\)\}/';
$_patternEndForeach = '/\{\/foreach\}/';
$_patternVar = '/\{@([\w]+)\}/';
if (preg_match($_patternForeach,$this->_tpl)){
if (!preg_match($_patternEndForeach,$this->_tpl)){
exit('ERROR:foreach语句没有闭合');
}
$this->_tpl = preg_replace($_patternForeach,'<?php foreach(\$this->_vars["$1"] as \$$2=>\$$3){?>',$this->_tpl);
$this->_tpl = preg_replace($_patternEndForeach,'<?php }?>',$this->_tpl);
//判断foreach是否有数据
if (preg_match($_patternVar,$this->_tpl)){
$this->_tpl = preg_replace($_patternVar,'<?php echo \$$1?>',$this->_tpl);
}
}
}
//解析include语句
private function parInclude(){
$_patternInclude = '/\{include\s+file=\"([\w\.\-]+)\"\}/';
if (preg_match($_patternInclude,$this->_tpl,$_file)){
if ((!file_exists($_file[1])) || empty($_file)){
exit('ERROR:文件'.$_file[1].'不存在');
}
$this->_tpl = preg_replace($_patternInclude,"<?php include '$1'?>",$this->_tpl);
}
}
//解析系统变量
private function parConfig(){
$_pattern = '/<!-- \{([\w]+)\} -->/';
if (preg_match($_pattern,$this->_tpl)){
$this->_tpl = preg_replace($_pattern,"<?php echo \$this->_config['$1'];?>",$this->_tpl);
}
}
}
1.引入模板解析类,并且实例化模板解析类,再将模板文件传入给模板解析类作为初始化参数,构造函数获取到模板文件类型,赋值给模板解析类的私有属性$_tpl
2.当在Template中调用Parser模板解析类中的compile()方法的时候,将编译文件名传递进去。
3.将模板文件放入编译文件之前,先解析tpl中的所有模板标签
public function compile($_parFile)
{
$this->parConfig();
$this->parInclude();
$this->parForeach();
$this->parCommon();
$this->parIf();
$this->parVar();
//生成编译文件之前解析模板内容
if (!file_put_contents($_parFile,$this->_tpl)){
exit('ERROR:编译文件生成出错');
}
}
已解析if语句为例:
{if $a}
<div>我是1号界面</div>
{else}
<div>我是2号界面</div>
{/if}
//解析if语句
private function parIf(){
$_pattenIf = '/\{if\s+\$([\w]+)\}/';
$_pattenEndIf = '/\{\/if\}/';
$_pattenElse = '/\{else\}/';
if (preg_match($_pattenIf,$this->_tpl)){
if (preg_match($_pattenEndIf,$this->_tpl)){
//匹配if开头
$this->_tpl = preg_replace($_pattenIf,'<?php if($this->_vars[\'$1\']){?>',$this->_tpl);
//匹配if结尾符并且更改为php形式
$this->_tpl = preg_replace($_pattenEndIf,"<?php };?>",$this->_tpl);
//匹配else
if (preg_match($_pattenElse,$this->_tpl)){
$this->_tpl = preg_replace($_pattenElse,"<?php }else{;?>",$this->_tpl);
}
}else{
exit('ERROR:IF语句没有关闭');
}
}
}
流程是先查找模板中是否存在{if $X}形式的模板标签,如果存在就查找{/if}
如果{/if}存在的情况在区分是否有else,然后通过字符串替换,将其变成PHP形式的输出
知识点:
preg_match() 函数用于进行正则表达式匹配,成功返回 1 ,否则返回 0 。
int preg_match( string pattern, string subject [, array matches ] )
preg_replace (正则表达式, 替换成, 字符串, 最大替换次数【默认-1,无数次】, 替换次数)
模板引擎的特点:
1.鼓励分离:让更个系统的可读性和维护性得到提高。
2.促进分工:使得程序员和美工去专心处理自己的设计。
3.比PHP更容易解析:编译文件和缓存文件加载更快、占资源更少。
4.增加安全性:可限制模板设计师进行不安全的操作的能力避免误删误访问等
一个PHP对应一个模板文件,经过调用模板类并且经过模板解析类之后,生成编译过后的php编译文件,为了加快访问速度,并且生成纯静态的HTML文件,作为缓存文件。
简易目录:
1.cache文件夹存放静态HTML文件,加快访问速度
2.config文件夹存放系统变量的XML文件
3.includes 存放模板解析类库
-------------Parser.class.php 模板文件解析类 用于解析tpl文件,将其解析成php文件
------------Templates.class.php 模板类 负责提供给index.php调用传递数据和调用模板文件
4.templates文件夹 存放tpl文件
5.Templates文件夹 存放解析过后的tpl文件,为PHP文件
6.Index.php 调用入口文件
7.template.inc.php 初始化模板文件
8.Test.php 测试文件类
一、定义初始化变量
template.inc.php
<?php//设置utf-8编码
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',ROOT_PATH.'/cache/');
//是否开启缓冲区
define('IS_CACHE',true);
//开启缓冲区
IS_CACHE&&ob_start();
//引入模板类
require ROOT_PATH.'/includes/Templates.class.php';
//实例化模板类
$_tpl = new Templates();
二.入口文件index.php
引入初始化文件
require dirname(__FILE__).'/template.inc.php';
global $_tpl;
//声明一个变量
$_name = '周起';
$_array = array(1,2,3,4,5,6,7);
//调用方法注入变量给模板
$_tpl->assign('name',$_name);
$_tpl->assign('content','学习PHP');
$_tpl->assign('a',1);
$_tpl->assign('array',$_array);
//载入tpl文件
$_tpl->display('index.tpl');
三、Templates.class.php
<?phpclass Templates{
//字段用于接收动态变量
private $_vars = array();
//保存系统变量
private $_config = array();
//创建构造方法验证各个目录是否存在
public function __construct()
{
if (!is_dir(TPL_DIR)||!is_dir(TPL_C_DIR)||!is_dir(CACHE)){
exit('ERROR:模板目录或编译目录或缓存目录不存在,请手动添加');
}
//解析xml系统变量
$_sxe = simplexml_load_file('config/profile.xml');
$_taglib = $_sxe->xpath('/root/taglib');
foreach ($_taglib as $tag){
$this->_config["$tag->name"] = $tag->value;
}
}
//用于注入变量
/**
* @param $_var模板变量名
* @param $_value模板变量值
*/
public function assign($_var,$_value)
{
if (isset($_var)||!empty($_var)
){
$this->_vars[$_var] = $_value;
}else{
exit('ERROR:请设置模板变量');
}
}
//display() 生成编译文件和缓存文件
/**
* @param $_file模板文件路径
*/
public function display($_file)
{
//设置模板路径
$_tplFile = TPL_DIR.$_file;
//判断模板文件是否存在
if (!file_exists($_tplFile)){
exit('ERROR:'.$_file.'文件不存在');
}
//生成编译文件路径
$_parFile = TPL_C_DIR.md5($_file).$_file.'.php';
//生成缓存文件
$_cacheFile = CACHE.md5($_file).$_file.'.html';
//当第二次相同文件的时候,直接载入缓存文件,避开编译
if (IS_CACHE){
//缓存文件和编译文件同时存在
if (file_exists($_cacheFile)&&file_exists($_parFile)){
//并且模板文件修改时间大于编译文件
if (filemtime($_cacheFile)>=filemtime($_parFile)&&filemtime($_parFile)>=filemtime($_tplFile)){
//直接载入静态文件
include $_cacheFile;
return ;
}
}
}
//当编译文件不存在或者模板文件被修改的时候 重新生成编译文件
if (!file_exists($_parFile ||filemtime($_parFile)<filemtime($_tplFile))){
//引入模板解析类
require ROOT_PATH.'/includes/Parser.class.php';
//实例化对象的时候将模板文件路径传递进去
$_parser = new Parser($_tplFile);
$_parser->compile($_parFile);
}
//载入编译文件
include $_parFile;
if (IS_CACHE){
//获取缓冲区数据放入缓存文件
file_put_contents($_cacheFile,ob_get_contents());
//清除缓冲区
ob_end_clean();
//载入缓存文件
include $_cacheFile;
}
}
}
当实例化Template对象的时候,会先判断各个目录是否存在
当index.php调用$_tpl->assign()方法的时候,调用Template对象中的assign方法,在Template中有一个私有属性$_var为数组类,用于存放assign中的参数
//用于注入变量
/**
* @param $_var模板变量名
* @param $_value模板变量值
*/
public function assign($_var,$_value)
{
if (isset($_var)||!empty($_var)
){
$this->_vars[$_var] = $_value;
}else{
exit('ERROR:请设置模板变量');
}
}
如果变量不存在,或者变量为空的话,提示设置模板变量,否则,以变量名为数组索引,变量值为相对索引的值,存放入$_var私有变量中。
如果出现相同变量名就会出现因为索引相同,出现覆盖的情况。
//声明一个变量
$_name = '周起';
//调用方法注入变量给模板
$_tpl->assign('name',$_name);
$_tpl->assign('content','学习PHP');
$_tpl->assign('content','不想成为码农');
die();
这个时候掉用assign()方法,assign()方法改写为
public function assign($_var,$_value)
{
if (isset($_var)||!empty($_var)){
$this->_vars[$_var] = $_value;
}else{
exit('ERROR:请设置模板变量');
}
print_r($this->_vars);
}
在网页端打开访问
当调用Template类中display()方法的时候,传递进来一个模板文件名称
$_tpl->display(‘index.tpl’);
/**
* @param $_file模板文件路径
*/
public function display($_file)
{
//设置模板路径
$_tplFile = TPL_DIR.$_file;
//判断模板文件是否存在
if (!file_exists($_tplFile)){
exit('ERROR:'.$_file.'文件不存在');
}
//生成编译文件路径
$_parFile = TPL_C_DIR.md5($_file).$_file.'.php';
//生成缓存文件
$_cacheFile = CACHE.md5($_file).$_file.'.html';
//当第二次相同文件的时候,直接载入缓存文件,避开编译
if (IS_CACHE){
//缓存文件和编译文件同时存在
if (file_exists($_cacheFile)&&file_exists($_parFile)){
//并且模板文件修改时间大于编译文件
if (filemtime($_cacheFile)>=filemtime($_parFile)&&filemtime($_parFile)>=filemtime($_tplFile)){
//直接载入静态文件
include $_cacheFile;
return ;
}
}
}
//当编译文件不存在或者模板文件被修改的时候 重新生成编译文件
if (!file_exists($_parFile ||filemtime($_parFile)<filemtime($_tplFile))){
//引入模板解析类
require ROOT_PATH.'/includes/Parser.class.php';
//实例化对象的时候将模板文件路径传递进去
$_parser = new Parser($_tplFile);
$_parser->compile($_parFile);
}
//载入编译文件
include $_parFile;
if (IS_CACHE){
//获取缓冲区数据放入缓存文件
file_put_contents($_cacheFile,ob_get_contents());
//清除缓冲区
ob_end_clean();
//载入缓存文件
include $_cacheFile;
}
}
1.接收到tpl模板名称,定位到该模板文件路径,并且检测模板文件是否存在。
2.并且同时声明两个变量用于存放模板编译文件路径和纯静态HTML缓存文件路径
3.模板文件和编译文件和静态文件规则是这样:
如果编译文件和缓存文件都不存在,直接载入编译文件,并且生成静态缓存文件
当编译文件不存在或者模板文件被修改的时候,重新生成编译文件,并且生成静态缓存文件
当第二次访问相同页面,并且编译文件和缓存文件同时存在,并且缓存文件的修改时间大于编译文件的时候,直接访问静态缓存文件
知识点:file_put_contents() 函数把一个字符串写入文件中。
缓存机制:http://www.cnblogs.com/usa007lhy/p/5421545.html(推荐)
filemtime() 函数返回文件内容上次的修改时间。
fileatime() 函数返回指定文件的上次访问时间。
当第一次或者模板文件发生改变的时候,重新解析模板文件,并且将其解析
//当编译文件不存在或者模板文件被修改的时候 重新生成编译文件
if (!file_exists($_parFile ||filemtime($_parFile)<filemtime($_tplFile))){
//引入模板解析类
require ROOT_PATH.'/includes/Parser.class.php';
//实例化对象的时候将模板文件路径传递进去
$_parser = new Parser($_tplFile);
$_parser->compile($_parFile);
}
<?phpclass Parser{
//保存模板内容
private $_tpl;
//接收模板文件路径
public function __construct($_tplFile)
{
if (!$this->_tpl = file_get_contents($_tplFile)){
exit('ERROR:模板文件读取错误');
}
}
public function compile($_parFile)
{
$this->parConfig();
$this->parInclude();
$this->parForeach();
$this->parCommon();
$this->parIf();
$this->parVar();
//生成编译文件之前解析模板内容
if (!file_put_contents($_parFile,$this->_tpl)){
exit('ERROR:编译文件生成出错');
}
}
//解析if语句
private function parIf(){
$_pattenIf = '/\{if\s+\$([\w]+)\}/';
$_pattenEndIf = '/\{\/if\}/';
$_pattenElse = '/\{else\}/';
if (preg_match($_pattenIf,$this->_tpl)){
if (preg_match($_pattenEndIf,$this->_tpl)){
//匹配if开头
$this->_tpl = preg_replace($_pattenIf,'<?php if($this->_vars[\'$1\']){?>',$this->_tpl);
//匹配if结尾符并且更改为php形式
$this->_tpl = preg_replace($_pattenEndIf,"<?php };?>",$this->_tpl);
//匹配else
if (preg_match($_pattenElse,$this->_tpl)){
$this->_tpl = preg_replace($_pattenElse,"<?php }else{;?>",$this->_tpl);
}
}else{
exit('ERROR:IF语句没有关闭');
}
}
}
//解析PHP代码注释
private function parCommon(){
$_pattern = '/\{#\}(.*)\{#\}/';
if (preg_match($_pattern,$this->_tpl)){
$this->_tpl = preg_replace($_pattern,'<?php /*$1*/;?>',$this->_tpl);
}
}
//解析普通变量
private function parVar(){
$_pattern = '/\{\$([\w]+)\}/';
if (preg_match($_pattern,$this->_tpl)){
$this->_tpl = preg_replace($_pattern,"<?php echo \$this->_vars['$1'];?>",$this->_tpl);
}
}
//解析foreach语句
private function parForeach(){
$_patternForeach = '/\{foreach\s+\$([\w]+)\(([\w]+),([\w]+)\)\}/';
$_patternEndForeach = '/\{\/foreach\}/';
$_patternVar = '/\{@([\w]+)\}/';
if (preg_match($_patternForeach,$this->_tpl)){
if (!preg_match($_patternEndForeach,$this->_tpl)){
exit('ERROR:foreach语句没有闭合');
}
$this->_tpl = preg_replace($_patternForeach,'<?php foreach(\$this->_vars["$1"] as \$$2=>\$$3){?>',$this->_tpl);
$this->_tpl = preg_replace($_patternEndForeach,'<?php }?>',$this->_tpl);
//判断foreach是否有数据
if (preg_match($_patternVar,$this->_tpl)){
$this->_tpl = preg_replace($_patternVar,'<?php echo \$$1?>',$this->_tpl);
}
}
}
//解析include语句
private function parInclude(){
$_patternInclude = '/\{include\s+file=\"([\w\.\-]+)\"\}/';
if (preg_match($_patternInclude,$this->_tpl,$_file)){
if ((!file_exists($_file[1])) || empty($_file)){
exit('ERROR:文件'.$_file[1].'不存在');
}
$this->_tpl = preg_replace($_patternInclude,"<?php include '$1'?>",$this->_tpl);
}
}
//解析系统变量
private function parConfig(){
$_pattern = '/<!-- \{([\w]+)\} -->/';
if (preg_match($_pattern,$this->_tpl)){
$this->_tpl = preg_replace($_pattern,"<?php echo \$this->_config['$1'];?>",$this->_tpl);
}
}
}
1.引入模板解析类,并且实例化模板解析类,再将模板文件传入给模板解析类作为初始化参数,构造函数获取到模板文件类型,赋值给模板解析类的私有属性$_tpl
2.当在Template中调用Parser模板解析类中的compile()方法的时候,将编译文件名传递进去。
3.将模板文件放入编译文件之前,先解析tpl中的所有模板标签
public function compile($_parFile)
{
$this->parConfig();
$this->parInclude();
$this->parForeach();
$this->parCommon();
$this->parIf();
$this->parVar();
//生成编译文件之前解析模板内容
if (!file_put_contents($_parFile,$this->_tpl)){
exit('ERROR:编译文件生成出错');
}
}
已解析if语句为例:
{if $a}
<div>我是1号界面</div>
{else}
<div>我是2号界面</div>
{/if}
//解析if语句
private function parIf(){
$_pattenIf = '/\{if\s+\$([\w]+)\}/';
$_pattenEndIf = '/\{\/if\}/';
$_pattenElse = '/\{else\}/';
if (preg_match($_pattenIf,$this->_tpl)){
if (preg_match($_pattenEndIf,$this->_tpl)){
//匹配if开头
$this->_tpl = preg_replace($_pattenIf,'<?php if($this->_vars[\'$1\']){?>',$this->_tpl);
//匹配if结尾符并且更改为php形式
$this->_tpl = preg_replace($_pattenEndIf,"<?php };?>",$this->_tpl);
//匹配else
if (preg_match($_pattenElse,$this->_tpl)){
$this->_tpl = preg_replace($_pattenElse,"<?php }else{;?>",$this->_tpl);
}
}else{
exit('ERROR:IF语句没有关闭');
}
}
}
流程是先查找模板中是否存在{if $X}形式的模板标签,如果存在就查找{/if}
如果{/if}存在的情况在区分是否有else,然后通过字符串替换,将其变成PHP形式的输出
知识点:
preg_match() 函数用于进行正则表达式匹配,成功返回 1 ,否则返回 0 。
int preg_match( string pattern, string subject [, array matches ] )
pattern | 正则表达式 |
subject | 需要匹配检索的对象 |
matches | 可选,存储匹配结果的数组, $matches[0] 将包含与整个模式匹配的文本,$matches[1] 将包含与第一个捕获的括号中的子模式所匹配的文本,以此类推 |
相关文章推荐
- 深入解析php模板技术原理【一】
- php smart模板技术入门教程
- php smart模板技术入门教程
- PHP入门教程之字符串处理技巧总结(转换,过滤,解析,查找,截取,替换等)
- ThinkPHP让../Public在模板不解析(直接输出)的方法[原创]_php实例_脚本之家
- PHP正则解析多重循环模板示例
- (转)PHP模板smarty简单入门教程
- PHP模板解析引擎--discuz
- 利用php缓冲区解析模板文件
- 【phpcms-v9】index.php文件分析-前台首页模板文件的解析过程分析
- PHP模板之Smarty安装与使用入门教程
- PHP--关于模板的原理和解析
- PHP-Web应用程序开发:使用模板(入门)
- 【phpcms-v9】index.php文件分析-前台首页模板文件的解析过程分析
- dedecms讲解-dedetag.class.php模板解析和属性解析,源码分析
- PHP模板之Smarty安装与使用入门教程
- PHP模板之Smarty安装与使用入门
- PHP模板之Smarty安装与使用入门教程
- WPF快速入门系列(7)——深入解析WPF模板
- PHP--关于模板的原理和解析