PHP--关于模板的原理和解析(php模板原理)
此内容用作笔记,以备日后查看,此内容为学习李炎恢课程而来,并非自己所创,如有问题请私信~
将PHP代码和静态HTML代码进行分离,使代码的可读性和维护性得到显著提高。
使用模板引擎:
我们所说的模板是Web模板,是主要由HTML标记组成的语言来编写的页面,但也有如何表示包含动态生成内容的方式(解析标签)。模板引擎是一种软件库,允许我们从模板生成HTML代码,并指定要包含的动态内容。
模板引擎的特点:
1.鼓励分离:让更个系统的可读性和维护性得到提高。
2.促进分工:使得程序员和美工去专心处理自己的设计。
3.比PHP更容易解析:编译文件和缓存文件加载更快、占资源更少。
4.增加安全性:可限制模板设计师进行不安全的操作的能力避免误删误访问等。
模板处理的流程图
创建模板:
1、创建初始模板所需要的文件夹和文件。
a) index.php主文件,用于编写业务逻辑。
b) template.inc.php模板初始化文件,用于初始模版信息。
c) templates目录存放所有的模板文件。
d) templates_c目录存放所有编译文件。
e) cache目录存放所有缓存文件。
f) includes目录存放所有的类文件。
g) config目录存放模板系统变量配置文件。
以下是源码:
主文件 index.php
<?php
//index.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_DIR', ROOT_PATH.'/cache/');
//定义缓存状态
define('IS_CACHE',true);
//设置缓存状态开关
IS_CACHE ? ob_start() : null; include ROOT_PATH.'/includes/Templates.class.php'; $_name = '方块李'; $array = array(1,2,3,4,5,6);
$_tpl = new Templates();
$_tpl->assign('name', $_name);
$_tpl->assign('a', 5>4);
$_tpl->assign('array', $array);
//显示
$_tpl->display('index.tpl');
?>
模板文件 HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title><!--{webname}--></title> </head>
<body>
{include "test.php"}
<!-- 这是HTML的注释 -->
{#}这是一条PHP的注释,在HTML页面里是不显示的,只会在生成的编译文件里显示{#}
我将被index.php导入
{$name}这个标签必须经过Parser.class.php这个解析类来解析它1
<br />
这里的内容改变了,为什么?
<br />
{if $a}
显示一号皮肤
{else}
显示二号皮肤
{/if}
<br />
{foreach $array(key,value)}
{@key}....{@value} <br />
{/foreach}
</body>
</html>
模板类:
//Templates.class.php
class Templates {
//创建一个存放数组的字段
private $_vars = array();
private $_config = array();
//创建一个构造方法
public function __construct(){
if(!is_dir(TPL_DIR) || !is_dir(TPL_C_DIR) || !is_dir(CACHE_DIR) ){
exit('ERROR:模板文件夹或者编译文件夹或者缓存文件夹没有创建!');
}
//获取系统变量
$_sxe = simplexml_load_file(ROOT_PATH.'/config/profile.xml');
$_taglib = $_sxe->xpath('/root/taglib');
foreach($_taglib as $_tag){
$this->_config["$_tag->name"] = $_tag->value;
}
} //创建变量注入方法
/**
* assign()变量注入方法
* @param $_var 要注入的变量名,对应.tpl文件中的需要替换的变量
* @param $_values 要注入的变量值
*/
public function assign($_var,$_values){
if(isset($_var) && !empty($_var)){
$this->_vars[$_var] = $_values; }else{
exit('ERROR:请设置变量名!');
} } //创建一个显示方法,用来显示编译后的文件
public function display($_file){
//设置模板文件的路径
$_tplFile = TPL_DIR.$_file;
//判断模板文件是否存在
if(!file_exists($_tplFile)){
exit('ERROR:模板文件不存在');
}
//设置编译文件名
$_parFile = TPL_C_DIR.md5($_file).$_file.'.php';
//设置缓存文件名
$_cacheFile = CACHE_DIR.md5($_file).$_file.'.html';
//判断缓存状态
if(IS_CACHE){
//判断缓存文件是否存在
if(file_exists($_cacheFile) && file_exists($_parFile)){
//是否修改过编译文件或者模板文件
if(filemtime($_cacheFile)>=filemtime($_parFile) && filemtime($_parFile)>filemtime($_tplFile)){
echo '以下是缓存文件内容';
echo "<br />";
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;
} }
}
解析类:
//Parser.class.php
class Parser {
//获取模板内容
private $_tpl;
//构造方法,初始化模板
public function __construct($_tplFile){
//判断文件是否存在
if(!$this->_tpl = file_get_contents($_tplFile)){
exit('ERROR:读取模板出错!');
} } //解析普通变量
private function parVar(){
$_pattern = '/\{\$([\w]+)\}/';
if (preg_match($_pattern,$this->_tpl)) {
$this->_tpl = preg_replace($_pattern,"<?php echo \$this->_vars['$1'] ?>",$this->_tpl);
}
}
//解析IF条件语句
private function parIf(){
//开头if模式
$_patternIf = '/\{if\s+\$([\w]+)\}/';
//结尾if模式
$_patternEnd = '/\{\/if\}/';
//else模式
$_patternElse = '/\{else\}/';
//判断if是否存在
if(preg_match($_patternIf, $this->_tpl)){
//判断是否有if结尾
if(preg_match($_patternEnd, $this->_tpl)){
//替换开头IF
$this->_tpl = preg_replace($_patternIf, "<?php if(\$this->_vars['$1']){ ?>", $this->_tpl);
//替换结尾IF
$this->_tpl = preg_replace($_patternEnd, "<?php } ?>", $this->_tpl);
//判断是否有else
if(preg_match($_patternElse, $this->_tpl)){
//替换else
$this->_tpl = preg_replace($_patternElse, "<?php }else{ ?>", $this->_tpl);
}
}else{
exit('ERROR:语句没有关闭!');
}
}
}
//解析foreach
private function parForeach(){
$_patternForeach = '/\{foreach\s+\$(\w+)\((\w+),(\w+)\)\}/';
$_patternEndForeach = '/\{\/foreach\}/';
//foreach里的值
$_patternVar = '/\{@(\w+)\}/';
//判断是否存在
if(preg_match($_patternForeach, $this->_tpl)){
//判断结束标志
if(preg_match($_patternEndForeach, $this->_tpl)){
//替换开头
$this->_tpl = preg_replace($_patternForeach, "<?php foreach(\$this->_vars['$1'] as \$$2=>\$$3){?>", $this->_tpl);
//替换结束
$this->_tpl = preg_replace($_patternEndForeach, "<?php } ?>", $this->_tpl);
//替换值
$this->_tpl = preg_replace($_patternVar, "<?php echo \$$1?>", $this->_tpl);
}else{
exit('ERROR:Foreach语句没有关闭');
}
}
}
//解析include
private function parInclude(){
$_pattern = '/\{include\s+\"(.*)\"\}/';
if(preg_match($_pattern, $this->_tpl,$_file)){
//判断头文件是否存在
if(!file_exists($_file[1]) || empty($_file[1])){
exit('ERROR:包含文件不存在!');
}
//替换内容
$this->_tpl = preg_replace($_pattern, "<?php include '$1';?>", $this->_tpl);
}
}
//解析系统变量
private function configVar(){
$_pattern = '/<!--\{(\w+)\}-->/';
if(preg_match($_pattern, $this->_tpl,$_file)){
$this->_tpl = preg_replace($_pattern,"<?php echo \$this->_config['$1'] ?>", $this->_tpl); }
} //解析单行PHP注释
private function parCommon(){
$_pattern = '/\{#\}(.*)\{#\}/';
if(preg_match($_pattern, $this->_tpl)){
$this->_tpl = preg_replace($_pattern, "<?php /*($1) */?>", $this->_tpl);
}
} //生成编译文件
public function compile($_parFile){
//解析模板变量
$this->parVar();
//解析IF
$this->parIf();
//解析注释
$this->parCommon();
//解析Foreach
$this->parForeach();
//解析include
$this->parInclude();
//解析系统变量
$this->configVar();
//生成编译文件
if(!file_put_contents($_parFile, $this->_tpl)){
exit('ERROR:编译文件生成失败!');
}
}
}
总结:模板引擎的整个过程:
1、当浏览器请求index.php文件时,实例化模板类对像 $_tpl = new Templates();
2、当Templates实例化的时候,生成两个数组,一个用来存放模板变量,另一个存放系统变量,通过构造方法,判断文件夹是否存在,同时通过XML文件将系统变量数组初始化
3、通过模板类Templates的注入方法,assign(),将对应模板index.tpl中变量的index.php的内容注入到模板类的私有变量,完成初始化
4、模板类Templates类显示方法display() 通过实例化解析类Parser,将取到的注入变量通过解析类进行解析(即替换)
5、解析(替换)后,将文件写入PHP、HTML混全文件
6、通过Templates类的显示方法将文件输出:
1、第一次执行显示方法时,将会把PHP、HTML混合文件,生成纯静态的缓存文件
2、调用缓存文件,显示页面
3、当浏览器再次调用显示方法时,首先根据各文件的最后修改时间,判断是否重新生成缓存文件或直接调用已存在的缓存文件
重点:
1、通过正则表达式进行字符串的替换
2、熟悉OOP
转:https://www.cnblogs.com/fkli/p/4810675.html
PHP--关于模板的原理和解析(php模板原理)的更多相关文章
- PHP--关于模板的原理和解析
此内容用作笔记,以备日后查看,此内容为学习李炎恢课程而来,并非自己所创,如有问题请私信~ 将PHP代码和静态HTML代码进行分离,使代码的可读性和维护性得到显著提高. 使用模板引擎: 我们所说的模板是 ...
- .NET/ASP.NET MVC Controller 控制器(深入解析控制器运行原理)
阅读目录: 1.开篇介绍 2.ASP.NETMVC Controller 控制器的入口(Controller的执行流程) 3.ASP.NETMVC Controller 控制器的入口(Controll ...
- 二、ASP.NET MVC Controller 控制器(一:深入解析控制器运行原理)
阅读目录: 1.开篇介绍 2.ASP.NETMVC Controller 控制器的入口(Controller的执行流程) 3.ASP.NETMVC Controller 控制器的入口(Controll ...
- java8Stream原理深度解析
Java8 Stream原理深度解析 Author:Dorae Date:2017年11月2日19:10:39 转载请注明出处 上一篇文章中简要介绍了Java8的函数式编程,而在Java8中另外一个比 ...
- NET/ASP.NET MVC Controller 控制器(一:深入解析控制器运行原理)
阅读目录: 1.开篇介绍 2.ASP.NETMVC Controller 控制器的入口(Controller的执行流程) 3.ASP.NETMVC Controller 控制器的入口(Controll ...
- DNS原理及其解析过程 精彩剖析
本文章转自下面:http://369369.blog.51cto.com/319630/812889 DNS原理及其解析过程 精彩剖析 网络通讯大部分是基于TCP/IP的,而TCP/IP是基于IP地址 ...
- GBDT算法原理深入解析
GBDT算法原理深入解析 标签: 机器学习 集成学习 GBM GBDT XGBoost 梯度提升(Gradient boosting)是一种用于回归.分类和排序任务的机器学习技术,属于Boosting ...
- 老调重弹:JDBC系列之<驱动加载原理全面解析) ----转
最近在研究Mybatis框架,由于该框架基于JDBC,想要很好地理解和学习Mybatis,必须要对JDBC有较深入的了解.所以便把JDBC 这个东东翻出来,好好总结一番,作为自己的笔记,也是给读者 ...
- DNS原理及其解析过程【精彩剖析】(转)
2012-03-21 17:23:10 标签:dig wireshark bind nslookup dns 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否 ...
随机推荐
- 11、Django实战第11天:templates模板继承
Django模板的继承,它首先定义一个整体的框架(父类),然后动态的部分(子类)只需要重写自己本身的代码就可以了. 1.在templates目录下创建base.html 2.把org-list.htm ...
- 【Ubuntu】使用root账户登录ubuntu
由于经常使用,所以写个博客记下来以便后来查看. 1.修改root账户密码:sudo passwd root,输密码 2.修改/usr/share/lightdm/lightdm.conf.d/50-u ...
- Oracle SQL*Loader commit point tips
http://www.dba-oracle.com/t_sql_loader_commit_frequency.htm - Question: Can I control the commit fr ...
- Codeforces 702 D Road to Post Office
题目描述 Vasiliy has a car and he wants to get from home to the post office. The distance which he needs ...
- 【分块】hdu5057 Argestes and Sequence
分块,v[i][j][k]表示第i块内第j位是k的元素数.非常好写.注意初始化 要注意题意,①第i位是从右往左算的. ②若x没有第i位,则用前导零补齐10位.比如103---->00000001 ...
- 【并查集】bzoj1015 [JSOI2008]星球大战starwar
倒着处理删点,就变成了加点,于是并查集. #include<cstdio> using namespace std; #define N 400001 int fa[N],kill[N], ...
- Bootstrap响应式布局
Bootstrap响应式布局可以使用栅格化系统,其实就是不同的列组合,配合起来便能组合出强大的功能,系统会自动分为最多12列,超出12列会作为一个整体另起一行,像制作表格table的合并列,功能跟co ...
- JavaScript的map循环、forEach循环、filter循环、reduce循环、reduceRight循环
1.map循环 let arr=[1,2,3,4]; arr.map(function(value,key,arr){ //值,索引,数组(默认为选定数组) return item; //如果没有re ...
- [Python爬虫] 之二十四:Selenium +phantomjs 利用 pyquery抓取中广互联网数据
一.介绍 本例子用Selenium +phantomjs爬取中广互联网(http://www.tvoao.com/select.html)的资讯信息,输入给定关键字抓取资讯信息. 给定关键字:数字:融 ...
- Git服务器分类
目录(?)[-] 服务器上的 Git 协议 本地协议 优点 缺点 SSH 协议 优点 缺点 Git 协议 优点 缺点 HTTPS 协议 优点 缺点 在服务器部署 Git 将纯目录转移到服务器 小型安装 ...