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
PHP--关于模板的原理和解析的更多相关文章
- PHP--关于模板的原理和解析(php模板原理)
此内容用作笔记,以备日后查看,此内容为学习李炎恢课程而来,并非自己所创,如有问题请私信~ 将PHP代码和静态HTML代码进行分离,使代码的可读性和维护性得到显著提高. 使用模板引擎: 我们所说的模板是 ...
- 高性能JavaScript模板引擎原理解析
随着 web 发展,前端应用变得越来越复杂,基于后端的 javascript(Node.js) 也开始崭露头角,此时 javascript 被寄予了更大的期望,与此同时 javascript MVC ...
- smarty模板引擎原理解析
//php 控制器文件 <?php//引入模板引擎文件include("20130304.php");$smarty =newTinySmarty();$qq_numbers ...
- 写一个迷你版Smarty模板引擎,对认识模板引擎原理非常好(附代码)
前些时间在看创智博客韩顺平的Smarty模板引擎教程,再结合自己跟李炎恢第二季开发中CMS系统写的tpl模板引擎.今天就写一个迷你版的Smarty引擎,虽然说我并没有深入分析过Smarty的源码,但是 ...
- JavaScript模板引擎原理
JavaScript模板引擎原理,几行代码的事儿 2013-12-03 16:35 by BarretLee, 650 阅读, 6 评论, 收藏, 编辑 一.前言 什么是模板引擎,说的简单点,就是一个 ...
- java8Stream原理深度解析
Java8 Stream原理深度解析 Author:Dorae Date:2017年11月2日19:10:39 转载请注明出处 上一篇文章中简要介绍了Java8的函数式编程,而在Java8中另外一个比 ...
- [django]模板template原理
django 中的render和render_to_response()和locals(): http://www.cnblogs.com/wangchaowei/p/6750512.html 什么是 ...
- [Vue源码]一起来学Vue模板编译原理(一)-Template生成AST
本文我们一起通过学习Vue模板编译原理(一)-Template生成AST来分析Vue源码.预计接下来会围绕Vue源码来整理一些文章,如下. 一起来学Vue双向绑定原理-数据劫持和发布订阅 一起来学Vu ...
- [Vue源码]一起来学Vue模板编译原理(二)-AST生成Render字符串
本文我们一起通过学习Vue模板编译原理(二)-AST生成Render字符串来分析Vue源码.预计接下来会围绕Vue源码来整理一些文章,如下. 一起来学Vue双向绑定原理-数据劫持和发布订阅 一起来学V ...
随机推荐
- 安卓升级提示 phoneGap APK软件更新提示
以下代码由PHP200 阿杜整理 package com.example.syzx; import java.io.BufferedReader; import java.io.File; imp ...
- RHEL6.4 KVM 桥接上网的设置
关闭网络管理器 chkconfig NetworkManager off ##和桥接有冲突,要关闭 service NetworkManager stop 修改eth0为物理网口,br0为桥接网 ...
- log4j2使用总结
一.Log4j有三个主要的组件:Loggers,Appenders和Layouts,这里可简单理解为日志级别,日志要输出的地方和日志格式 1. Logger Logger的日志级别有6级,分别是TRA ...
- 为Delphi程序增加UAC功能(管理员身份运行exe)
相关资料:http://bbs.csdn.net/topics/320071356# 操作方法: 在Source\VCL目录下应该有这样两个文件sample.manifest和WindowsXP.rc ...
- Spring MVC BeanNameUrlHandlerMapping example
In Spring MVC, BeanNameUrlHandlerMapping is the default handler mapping mechanism, which maps URL re ...
- WebForm中如何防止页面刷新,后退导致的重复提交
当用户按下浏览器中的 F5 键刷新当前页面时,对这一过程进行检测所需的操作步骤.页面刷新是浏览器对特定用户操作(按 F5 键或单击"刷新"工具栏按钮)的响应.页面刷新操作是浏览器内 ...
- SPOJ 375 (树链剖分 - 边权剖分 - 修改单边权)
题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28982#problem/I 给你一棵有边权的树,有两个操作:一个操作是输出l到 ...
- VirtualBox虚拟磁盘扩容
1. cmd中运行 VBoxManage modifyhd D:\我的资料库\Documents\VirtualBox VMs\ubuntu\ubuntu.vdi --resize 提示错误 Syn ...
- Hadoop 2.0+YARN启动脚本分析与实战经验
start-all.sh脚本现在已经废弃,推荐使用start-dfs.sh和start-yarn.sh分别启动HDFS和YARN. 在新一代的Hadoop里面HDFS称为了统一存储的平台,而YARN成 ...
- rsync服务架设(数据同步|文件增量备份)
近期由于业务需要,需要将两台服务器数据保持同步.方案有很多,rsync是其中一种解决方案,本文对rsync的安装及配置进行简单说明,其他实现方式有兴趣可以研究.以下是本文提纲,供参考: rsy ...