Ursprung der Template-Engine
In den frühen Tagen der Entwicklung von WEB-Anwendungen in PHP wurden PHP-Code und HTML-Vorlagen gemischt. Die Geburt der Template-Engine bestand hauptsächlich darin, das Ganze zu lösen Das Problem der Trennung von Back-End und Front-End besteht darin, dass sich Entwicklung und Künstler trennen und zusammenarbeiten können (obwohl der größte Teil der endgültigen Vorlagenarbeit immer noch durch Back-End abgeschlossen wird). Endentwickler), wodurch die Entwicklungseffizienz verbessert und die Wartung erleichtert wird.
Mit dem schnellen Wachstum von PHP gibt es immer mehr Template-Engines, aber sie werden grob in zwei Typen unterteilt: interpretiert und kompiliert. Die meisten aktuellen Mainstream-Template-Engines werden kompiliert, das heißt, sie werden zuerst kompiliert Die Vorlage wird zur Ausführung in eine PHP-Datei kompiliert. Solange sich die Vorlagendatei selbst nicht ändert, ist eine Neukompilierung wie beim alten Smarty nicht erforderlich. Eine interpretierte Template-Engine führt bei jeder Ausführung einen Template-Parsing-Prozess durch, wie zum Beispiel tinybutstrong.
ThinkPHP verfügt von Anfang an über eine integrierte Template-Engine, die auf der XML-Tag-Bibliothekstechnologie basiert. Sie wurde schon früh von Struts referenziert und wird durch die Aufnahme neuer Ideen ständig weiterentwickelt.
So wählen Sie eine Template-Engine aus
Derzeit sind Mainstream-Frameworks mit Template-Engine-Komponenten ausgestattet oder kapseln die Implementierung von Template-Engines, sodass Sie sich für eine integrierte Lösung entscheiden sollten Beste Auswahl, Funktionalität und Stabilität sind garantiert. Derzeit sind die beliebtesten Template-Engines die Blade-Template-Engine von Laravel und die Twig-Template-Engine von Symfony.
Durch die Installation der Template-Engine-Erweiterung können Sie problemlos Template-Engines wie Angular, Twig und Blade in ThinkPHP verwenden oder sogar PHP-Dateien direkt als Vorlagen verwenden, ohne überhaupt eine Template-Engine zu verwenden.
Aufgrund der Beliebtheit der drei großen Front-End-Frameworks (React/Vue/Angular) hat sich in den letzten Jahren die getrennte Entwicklung von Front-End und Back-End allmählich zum Mainstream entwickelt wurde für die API-Entwicklung positioniert, was dazu führte, dass das Konzept der Template-Engine geschwächt wurde. Die Template-Engine von ThinkPHP Version 5.1 wurde einer internen Rekonstruktion unterzogen, wodurch Template-Tags einfacher zu verwenden sind und näher an der PHP-Syntax liegen.
Zumindest für die meisten neuen Anwendungen sollten Sie ein gängigeres Front-End- und Back-End-Trennungsdesign wählen, um den Druck auf den Server so weit wie möglich zu reduzieren und das Testen des Front-Ends und des Back-Ends zu erleichtern separat. Sie werden versehentlich Produkte auf dem Markt sehen, die Vue und ThinkPHP verwenden (in früheren Ausgaben von ThinkPHP Developer Weekly wurde über mehrere davon berichtet). Wenn Sie einige alte Projekte pflegen, insbesondere Content-Management-Produkte, können Sie weiterhin Template-Engines verwenden.
Angesichts dieser Situation verfügt die nächste Version des ThinkPHP-Frameworks nicht über eine integrierte Template-Engine. Entwickler, die die Template-Engine verwenden müssen, können jedoch weiterhin die offizielle unabhängige Think-Template-Klassenbibliothek verwenden. Informationen zur spezifischen Verwendung finden Sie in diesem Artikel.
In den folgenden Abschnitten werden wir hauptsächlich die Verwendung und Techniken der integrierten Template-Engine von ThinkPHP zusammenfassen.
Vorlagenausführungsprozess
Die Aufrufbeziehung der Template-Engine innerhalb des Systems ist wie folgt:
视图(View) <=> 模板驱动(Driver) <=> 模板引擎(Template)
Eine Treiberebene wird zwischen der Ansicht und dem hinzugefügt Template-Engine, sodass sie problemlos durch andere Template-Engines ersetzt werden kann. Normalerweise sind die Zuweisungs-/Abrufmethoden und andere Methoden, die wir im Controller aufrufen, tatsächlich die Methoden der aufgerufenen thinkView-Klasse. Bei Bedarf können Sie die Template-Engine-Klasse natürlich auch direkt im Controller betreiben, der Wechsel zu anderen Template-Engines ist jedoch nicht bequem.
Nehmen wir als Beispiel die Abrufmethode:
think\Controller->fetch(); think\View->fetch(); think\view\driver\Think->fetch(); think\Template->fetch();
Wenn Sie beim Aufruf des Abrufs nicht den vollständigen Namen der zu rendernden Vorlagendatei übergeben Methode wird im dritten Schritt automatisch die zu rendernde Vorlagendatei identifiziert.
Der kritischste Schritt ist natürlich der letzte Schritt. Der Prozess der Vorlagenkompilierung und -ausführung wird durch die
think\Template->fetch();
-Methode abgeschlossen.
1. Bestimmen und lesen Sie den Seiten-Rendering-Cache
Wenn für die aktuelle Vorlage ein Seiten-Ausgabe-Cache festgelegt ist und gerendert und ausgegeben wurde, wird der Ausgabeinhalt im Cache gelesen und direkt ausgeben.
if (!empty($this->config['cache_id']) && $this->config['display_cache']) { // 读取渲染缓存 $cacheContent = $cache->get($this->config['cache_id']); if (false !== $cacheContent) { echo $cacheContent; return; } }
2. Suchen Sie die Vorlagendatei
Der eigentliche Vorgang zur Positionierung der Vorlagendatei wird durch die parseTemplateFile-Methode der Template-Engine-Klasse implementiert. Die Logik dieser Methode ähnelt tatsächlich der parseTemplate-Methode von Die Ansichtstreiberklasse Wenn die endgültige Vorlagendatei nicht vorhanden ist, wird eine Ausnahme „Vorlagendatei nicht vorhanden“ ausgelöst.
$template = $this->parseTemplateFile($template);
3. Bestimmen Sie den Kompilierungscache
Wenn die aktuelle Vorlagendatei kompiliert wurde, wird beurteilt, ob der Cache noch gültig ist, eine Wiederholung ist nicht erforderlich Führen Sie das Parsing durch und lesen Sie direkt den zwischengespeicherten Parsing-Inhalt. Dies erfolgt durch die checkCache-Methode.
if (!$this->checkCache($cacheFile)) { // 缓存无效 重新模板编译 $content = file_get_contents($template); $this->compiler($content, $cacheFile); }
4. Vorlagenkompilierung und Zwischenspeicherung
Dieser Schritt ist die Kernverbindung der Vorlagen-Engine und die komplexeste Funktion. Er wird durch die Compiler-Methode vervollständigt, die hauptsächlich die aktuelle Vorlagendatei analysiert Die Syntax des Template-Tags besteht aus ausführbarem PHP-Code, und dann wird eine Template-Parsing-Cache-Datei generiert, bei der es sich um die sogenannte Template-„Kompilierung“ handelt, die viel Technologie zum Ersetzen regulärer Ausdrücke verwendet , aber die Vorteile Basierend auf dem Caching-Prinzip des einmaligen Parsens mehrerer Aufrufe hat der Leistungsaufwand beim Parsen von Vorlagen grundsätzlich keinen Einfluss auf die tatsächliche Leistung.
Der Schlüsselcode der Vorlagenkompilierungsmethode ist die Parse-Methode. Die Parse-Methode ist für das Parsen der Tags in der Vorlagendatei und das anschließende Schreiben in die Kompilierungs-Cache-Datei verantwortlich Standard und unterstützt die Erweiterung.
5. Lesen Sie den Kompilierungscache
模板编译的过程只是生成了模板编译缓存文件,并没有真正载入模板,这一步骤就是载入模板编译缓存,然后导入模板变量。实现方法可以参考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 name="value" >...</tagLib:tagName> // 开放类型标签 <tagLib:tagName name="value" />
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",'<br/>',$content); })->fetch(); }
模板继承的block是否支持嵌套
目前模板继承的block无法支持嵌套功能,你应该使用其它方式解决。
Das obige ist der detaillierte Inhalt vonImplementierung der ThinkPHP-Template-Engine und häufige Probleme. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!