php模板解析引擎 单独,ThinkPHP模板引擎实现和常见问题

模板引擎由来

早期做PHP开发WEB应用都是把PHP代码和HTML模板混在一起,模板引擎的诞生主要就是为了解决后端与前端的完全分离(现在来看其实是属于不完全分离)的问题,让开发与美工可以分工合作(虽然实际上最终模板工作大多仍然是由后端开发人员完成),从而提高开发效率和便于维护。

伴随着PHP的快速成长,模板引擎也越来越多,但大致分为解释型和编译型两种,目前主流的模板引擎大多数是编译型的,也就是会先把模板编译成PHP文件执行,只要模板文件本身不变化,就不需要重新编译,例如老牌的Smarty。解释型的模板引擎每次执行的时候都会进行模板解析流程,例如小强(tinybutstrong)。

ThinkPHP从一开始就内置了一个基于XML标签库技术的编译型模板引擎,早期参考自Struts,并且不断在汲取新的思想不断进化。

如何选择模板引擎

目前主流框架都带有模板引擎组件或者封装了模板引擎的实现,因此选择内置的解决方案是最佳之选,功能和稳定性都有保证。目前最流行的模板引擎当属Laravel自带的Blade模板引擎,以及Symfony自带的Twig模板引擎。

通过安装模板引擎扩展,你可以在ThinkPHP中轻松使用包括Angular、Twig和Blade在内的模板引擎,甚至完全不使用模板引擎而是直接用PHP文件作为模板。

因为近几年三大前端框架(React/Vue/Angular)的流行,前后端分离开发逐渐成为主流,因此从ThinkPHP5.0开始定位为API开发而设计,导致模板引擎的概念已经被弱化了。ThinkPHP5.1版本的模板引擎进行过一次内部的重构,使得模板标签更加易用和接近PHP语法。

至少对于大部分新的应用来说,应该选择更主流的前后端分离设计,尽量减轻服务端的压力,也更方便前后端单独测试。你会在市面上不经意的看到采用Vue和ThinkPHP的产品(之前几期的ThinkPHP开发者周刊曾经报道过几个)。如果是维护一些老项目尤其是内容管理产品的时候,仍然可能会用到模板引擎。

鉴于这种情况,下一个版本的ThinkPHP框架将不会内置模板引擎,但有需要使用模板引擎的开发者仍然可以使用官方独立出来的think-template类库,具体使用可以参考这篇文章。

后面的篇幅,我们主要来总结下ThinkPHP内置的模板引擎的使用和技巧。

模板执行流程

系统内部的模板引擎调用关系如下:视图(View) <=> 模板驱动(Driver) <=> 模板引擎(Template)

视图和模板引擎之间增加了一个驱动层,所以可以很方便的替换其它的模板引擎。通常我们在控制器中调用的assign/fetch等方法其实都是调用的think\View类的方法。当然,如果有必要,你也完全可以直接在控制器中操作模板引擎类,只是不方便切换其它模板引擎。

以fetch方法为例,我们看下最终的调用过程:think\Controller->fetch();

think\View->fetch();

think\view\driver\Think->fetch();

think\Template->fetch();

如果你调用fetch方法的时候没有传入要渲染的完整模板文件名,则会在第三步的时候自动识别要渲染的模板文件。

很显然,最关键是最后一步,模板编译和执行的流程则全部由think\Template->fetch();

方法完成,这个环节大体又可以分成几个流程。

1、判断和读取页面渲染缓存

如果当前模板设置了页面输出缓存并且已经渲染输出过,如果是则会读取缓存中的输出内容直接输出。if (!empty($this->config['cache_id']) && $this->config['display_cache'])

{

// 读取渲染缓存

$cacheContent = $cache->get($this->config['cache_id']);

if (false !== $cacheContent) {

echo $cacheContent;

return;

}

}

2、定位模板文件

定位实际的模板文件操作由模板引擎类的parseTemplateFile方法实现,这个方法的逻辑其实和视图驱动类的parseTemplate方法是类似的,如果最终的模板文件不存在则会抛出一个模板文件不存在的异常。$template = $this->parseTemplateFile($template);

3、判断编译缓存

如果当前的模板文件已经编译过,会判断缓存是否还有效,有效的话就不用重复解析直接读取缓存的解析内容。由checkCache方法负责完成。if (!$this->checkCache($cacheFile)) {

// 缓存无效 重新模板编译

$content = file_get_contents($template);

$this->compiler($content, $cacheFile);

}

4、模板编译并缓存

这一步骤是模板引擎最核心的环节,也是功能最复杂的地方,由compiler方法负责完成,主要是解析当前模板文件中的模板标签语法为PHP可执行代码,然后生成一个模板解析缓存文件,也就是所谓的模板“编译”,其中使用了大量的正则表达式替换技术,虽然正则解析有一定的性能开销,但得益于一次解析多次调用的缓存原理,基本上模板解析的性能开销不会影响实际使用的性能。

模板编译方法的关键代码是parse方法,parse方法负责对模板文件中的标签进行解析,然后写入编译缓存文件,编译缓存默认使用的是文件缓存,支持扩展。

5、读取编译缓存

模板编译的过程只是生成了模板编译缓存文件,并没有真正载入模板,这一步骤就是载入模板编译缓存,然后导入模板变量。实现方法可以参考think\template\driver\File类的read方法。public function read($cacheFile, $vars = []){

$this->cacheFile = $cacheFile;

if (!empty($vars) && is_array($vars)) {

// 模板阵列变量分解成为独立变量

extract($vars, EXTR_OVERWRITE);

}

//载入模版缓存文件

include $this->cacheFile;

}

6、缓存页面输出

如果当前模板渲染的时候开启了页面输出缓存,就会这一步生成页面渲染后的输出缓存。

模板编译原理

我们来了解下ThinkPHP的模板引擎的实现原理。前面提到过,ThinkPHP的模板引擎最早源于Struts的设计理念,基于XML和标签库的技术实现。在设计模板语言的时候使用系统固定的标签来实现普通的变量输出功能(所以称之为普通标签),而利用XML标签库技术实现的动态标签用于变量的控制或者条件判断输出。

普通标签的解析是由think\Template类的parseTag方法完成的,主要实现了下面几个模板功能:

变量输出(包括系统变量);

函数过滤;

变量运算;

三元运算;

执行函数以及输出结果;

模板注释;

标签库采用的是动态扩展的设计方案,采用了类似XML的闭合/开放定义方式(这个其实也是目前模板引擎的一个局限所在),例如下面的这个:// 闭合类型标签

...

// 开放类型标签

tagLib就代表了一个标签库(类),后面的tagName标签就表示该标签库下面的某个标签(通常对应了标签库类的某个方法),后面的属性就是该标签支持的属性定义。具体该标签的属性和功能则完全由标签库类的这个方法来决定。

可以在模板开头明确指出,当前模板使用了哪些标签库{taglib name="html,article" /}

所以要扩展模板引擎的功能只需要通过扩展一个标签库类就可以了。大多数的内容管理系统都会定义一套自己的模板二次开发标签,利用标签库功能就可以很方便的定义一套属于自己的标签功能。

系统内置了一套标签库Cx,主要用于文件包含、条件控制、循环输出等功能。内置标签库在使用的时候无需引入,而且在使用的时候可以省略标签库前缀,例如:{foreach $list as $key=>$vo }

{$vo.id}:{$vo.name}{/foreach}

这个模板语法相信PHP开发的很容易上手,上面的标签解析由think\template\taglib\Cx类的tagForeach方法完成,该方法的返回值是一个字符串,其实就是最终会解析成的一段包含变量的PHP可执行代码。

到这里,模板引擎的执行过程和原理现在基本就明白了,剩下的就是模板标签的解析细节,考验的就是正则表达式的掌握程度了。本文就不做深入了,有兴趣的朋友可以去看一些正则表达式的相关资料(例如这本《正则指引》,开发者周刊第14期也提供了一些在线的正则工具)。

遵循的原则

使用模板引擎,要尽量遵循几个重要的原则。

不要在模板文件中添加任何的业务逻辑

模板的作用主要是进行模板变量的控制和输出,不要在模板文件中添加业务逻辑代码。

明确指定渲染模板

养成明确指定渲染模板的好习惯,避免当方法名发生变化,或者被其它方法调用的时候发生错误。也不易受模板命名规范的影响。

变量统一赋值

使用assign方法或者在view助手函数的时候,统一一次传入模板变量。不要多次赋值,以免混乱。

系统变量无需赋值到模板

对于系统变量(包括请求变量、$_SESSION和$_SERVER等系统变量)无需进行模板变量赋值,可以直接在模板中输出。

常见问题

这里总结一下经常会遇到的一些常见问题。

修改定界符

可以通过模板配置文件修改模板标签的定界符。

例如,修改普通标签定界符'tpl_begin' => '{{', // 模板引擎普通标签开始标记

'tpl_end' => '}}', // 模板引擎普通标签结束标记

标签库标签定界符'taglib_begin' => '

'taglib_end' => '}>', // 标签库标签结束标记

保持原样输出

如果担心模板标签和JS代码产生混淆,可以使用literal标签{literal} Hello,{$name}! {/literal}

页面最终会直接输出Hello,{$name}!

避免输出转义

5.1版本为了避免XSS攻击,默认对模板变量的输出使用了安全转义,默认的转义函数是htmlentities,你可以通过更改default_filter配置改变默认的转义函数。

如果你不需要对某个模板变量输出进行转义(例如包含了HTML代码),可以使用:{$data.content|raw}

分页输出就是一个需要输出HTML的典型例子,因此必须增加|raw。

关于模板主题

新版取消了原来的模板主题功能,因为模板主题对模板引擎来说,其实无非是一个模板目录,完全可以根据自己的需求控制。

例如$theme = 'blue';$this->fetch('/' . $theme. '/user/index');

或者动态设置模板引擎的view_path参数$this->view->config('view_path', \think\facade\App::getModulePath(). 'view/'. $theme . '/');

如何关闭模板缓存

由于是编译型模板引擎,模板标签不能被直接执行,必须编译成PHP语法后才能执行,因此不能关闭模板编译缓存,模板引擎每次执行渲染的时候会检测模板文件是否有变化,当模板文件的修改时间超过模板编译缓存的修改时间后,模板引擎会自动更新编译缓存。

但你可以强制模板引擎每次都重新编译,只需要在配置文件中设置'tpl_cache' => false, // 关闭模板缓存

使用PHP作为模板引擎

如果不希望使用内置的模板引擎,直接使用PHP作为模板引擎,可以配置'type' => 'php',

配置使用PHP作为模板引擎的话,是不会生成模板编译缓存的。

如何使用第三方模板引擎

系统支持扩展其它的第三方模板引擎,你只需要开发一个模板引擎驱动,目前已经支持的第三方模板引擎包括Smarty、Twig和Blade。

如何跨模块输出模板

要渲染一个跨模块的模板文件,你需要使用

// 渲染user模块的模板文件$this->fetch('User@order/index');

是否支持变量运算

可以直接在模板文件中进行变量运算而不需要在控制器中进行运算后再赋值都模板变量输出。{$score1+$score2}

{$count++}

文件包含是否支持变量

include标签可以支持传入变量,但只能使用{include file="$file" /}

而不能使用{include file="file_$name" /}

可以支持模板输出替换么

支持两个方式对模板进行输出替换,如果需要对模板文件的内容进行替换,可以配置:'tpl_replace_string' => [

'__STATIC__'=>'/static',

'__JS__' => '/static/javascript',

]

如果是对模板渲染输出的内容进行替换,可以在控制器中使用视图过滤功能:public function index(){

// 使用视图输出过滤

return $this->filter(function($content){

return str_replace("\r\n",'
',$content);

})->fetch();

}

模板继承的block是否支持嵌套

目前模板继承的block无法支持嵌套功能,你应该使用其它方式解决。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/523403.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mycat设置开机自启

接上一篇&#xff1a;实战_21_Mycat_MySql更新数据库失败 --read-only https://blog.csdn.net/weixin_40816738/article/details/100059688 下载mycat wget http://dl.mycat.io/1.6.5/Mycat-server-1.6.5-release-20180122220033-linux.tar.gz解压即安装mycat tar -zxf Mycat…

最近,京东AR又爆出哪般神奇?

戳蓝字“CSDN云计算”关注我们哦&#xff01;作者 | 刘晶晶只用一部手机就可在线“试用”口红&#xff0c;效果堪比美妆男主李佳琪&#xff0c;厉不厉害&#xff1f;只要轻轻一点就可一目了然购买的家具在家中摆放的效果怎样&#xff0c;神不神奇&#xff1f;时间飞快&#xff…

zookeeper开机自启动

编辑rc.local vim /etc/rc.d/rc.local2.需要指定jdk路径以及zookeeper启动路径 export JAVA_HOME/app/jdk1.8.0_144 /app/zookeeper-3.4.11/bin/zkServer.sh start3. 启动zookeeper cd /app/zookeeper-3.4.11/bin ./zkServer.sh start查看zk启动状态 /app/zookeeper-3.4.11…

绘制曲线 matlab,matlab绘制曲线图文

二维图形 三维图形 特殊二、三维图形 图形处理 实例 - 1 1.曲线图 Matlab作图是通过描点、连线来实现的,故在 画一个曲线图形之前,必须先取得该图形上的一系 ......例1 在0≤x≤2区间内,绘制曲线 y2e- MATLAB绘图 二维数据曲线图...第5讲 MATLAB绘图 电气工程系 李颖琼 6.1.1绘…

10分钟读懂什么是容器云?

戳蓝字“CSDN云计算”关注我们哦&#xff01;作者 | 宝哥devops运维来源 | http://t.cn/ECwSNgj容器技术是近几年云行业发展中不可缺少的一环。Docker和k8s的大热极大可能会推动云计算PAAS层的完善和普及。那么容器云到底是怎样的技术形态&#xff1f;究竟是概念还是可落地的应…

企业实战_19_MyCat初始化ZK并配置Mycat支持ZK

接上一篇&#xff1a;企业实战_18_MyCat_ZK集群安装部署 https://gblfy.blog.csdn.net/article/details/100075631 文章目录一、初始化集群中的数据1. 配置复制2. 初始化zookeeper集群中的数据二、验证数据是否被初始化到集群中2.1. 进入mycat01服务节点2.2. 使用ls命令查看当前…

Hadoop精华问答 | 基于Hadoop的数据中心有什么好处?

戳蓝字“CSDN云计算”关注我们哦&#xff01;2006年项目成立的一开始,“Hadoop”这个单词只代表了两个组件——HDFS和MapReduce。到现在的13个年头,这个单词代表的是“核心”&#xff0c;今天我们就来看看关于Hadoop的精华问答。1Q&#xff1a;基于Hadoop的数据中心有什么好处&…

企业实战_20_MyCat使用HAPpoxy对Mycat负载均衡

上一篇&#xff1a;企业实战_19_MyCat初始化ZK并配置Mycat支持ZK https://gblfy.blog.csdn.net/article/details/100087824 解决了引入多个mycat节点之间配置文件信息同步问题 如何在多个mycat之间进行负载均衡的问题&#xff1f; 在某一个mycat节点出现宕机之后&#xff0c;我…

安全,从写第一行代码开始!

戳蓝字“CSDN云计算”关注我们哦&#xff01;作者 | 刘晶晶伴随5G时代的脚步渐进&#xff0c;物联网发展也将成井喷式增长&#xff0c;“网络安全”这个老生常谈的话题似乎进入了新阶段。数据是天使&#xff1f;还是魔鬼&#xff1f;归根结底&#xff0c;没有安全保障的物联网终…

python模块里的函数及说明,Python模块 time与datetime模块的函数说明及使用实例

time模块模块time包含用于获取当前时间,操作时间和日期.从字符串中读取日期,将日期格式化为字符串的函数.日期可表示为实数,也可表示为包含9个整数的元组例如tuple(2018,12,24,12,2,56,-1,-1,-1)------------------------------------------------------索引 字段 值0-----年--…

Linux zookeeper下载、单点部署

说明地址ziphttp://mirror.bit.edu.cn/apache/zookeeper/stable/apache-zookeeper-3.5.5-bin.tar.gz命令下载wget http://mirror.bit.edu.cn/apache/zookeeper/stable/apache-zookeeper-3.5.5-bin.tar.gz http://archive.apache.org/dist/zookeeper/zookeeper-3.5.7/apache-zoo…

聚科技精英,享开源之美- 2019 Open Source Summit 主题演讲+项目亮点

2019年6月24-26日&#xff0c;在上海世博中心&#xff0c;由Linux基金会主办的LinuxCon ContainerCon CloudOpen大会&#xff08;简称LC3&#xff09;将与CNCF主办的KubeCon CloudNativeCon大会合体&#xff0c;自此&#xff0c;大会正式更名为KubeCon CloudNativeCon Ope…

php写linux应用程序,Linux应用程序使用写文件调试程序的方法

Linux&#xff0c;一切皆文件&#xff0c;那么在Android系统本身&#xff0c;也是Linuxjava罢了&#xff0c;也是在Linux的运行环境下。通常&#xff0c;我们在调试程序的都会使用printf。在Android中&#xff0c;我们会去使用logcat&#xff0c;现在&#xff0c;给大家介绍一种…

_Mycat-Web之UI监控

接上一篇&#xff1a;企业实战_19_Mycatkeepalived 安装配置验证 https://blog.csdn.net/weixin_40816738/article/details/100103518 文章目录1、zip下载2、wget 下载方式3、解压4、在安装mycat-web之前首先要安装一下5、设置zookeeper服务路径6、启动mycat-web7、浏览器验证8…

企业实战_21_MyCat_keepalived 安装配置验证

接上一篇&#xff1a;企业实战_20_MyCat使用HAPpoxy对Mycat负载均衡 https://gblfy.blog.csdn.net/article/details/100087884 主机名IP地址角色mycat192.168.43.32MYCAT MYSQL,ZK,Haproxy,Keepalivednode1192.168.43.104MYSQL,ZKnode2192.168.43.217MYSQL,ZKnode3192.168.43.1…

为什么说 5G 是物联网的时代?

受 5G 冲击最大的领域终将会是谁&#xff1f;作者 | 屠敏 整理出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;提及当前科技圈有哪些热点词&#xff0c;那 5G 必是其中之一。6 月 6 日&#xff0c;工业和信息化部正式向中国移动、中国联通、中国电信和中国广电发布…

命令行给php脚本传参,如何在CLI命令行下运行PHP脚本,同时向PHP脚本传递参数?...

标签&#xff1a;c t sp get int name php test print root enter//命令行输入输出流fwrite(STDOUT,"Enter your name:");$name trim(fgets(STDOUT));fwrite(STDOUT,"hello,$name");*/echo$argc;if ($argc > 1){print_r($argv);}?…

企业实战_24_MyCat实现读写分离

接上一篇&#xff1a;企业实战_23_MyCat SQL防火墙 https://gblfy.blog.csdn.net/article/details/100074335 文章目录一、MyCat读写分离操作流程二、环境部署安排&#xff1a;三、主机操作103(node3)3.1. 数据备份3.2. 将node3.sql复制到节点53.3. 导入数据3.4. 在查看是否创建…

c#中计算三角形面积公式,C#源代码—三角形面积、圆的面积

三角形面积、圆的面积using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace _2{public abstract class shape{private string mc;public shape(string s){Mc s;}public string Mc{get{return mc;}set{mc value;}}public double Are…

Storm精华问答 | 为什么要用Storm?不用Spark?

戳蓝字“CSDN云计算”关注我们哦&#xff01;Apache Storm是一个分布式实时大数据处理系统。Storm设计用于在容错和水平可扩展方法中处理大量数据。它是一个流数据框架&#xff0c;具有最高的摄取率。今天&#xff0c;我们就挑一些Storm的安装配置问题来看看吧。1Q&#xff1a;…