面向开发者的Twig¶
本章介绍的是Twig的API,而不是模板语言。对于那些实现应用程序模板接口的人,而不是那些正在创建Twig模板的人来说,这将是最有用的参考。
基础¶
Twig使用一个名为 环境 (等级) \Twig\Environment
). 此类的实例用于存储配置和扩展,并用于加载模板。
大多数应用程序都会创建一个 \Twig\Environment
对象,并使用该对象加载模板。在某些情况下,使用不同的配置同时使用多个环境可能会很有用。
配置Twig以加载应用程序模板的典型方法大致如下:
require_once '/path/to/vendor/autoload.php';
$loader = new \Twig\Loader\FilesystemLoader('/path/to/templates');
$twig = new \Twig\Environment($loader, [
'cache' => '/path/to/compilation_cache',
]);
这将创建一个具有默认配置和在中查找模板的加载程序的模板环境 /path/to/templates/
目录。可以使用不同的加载程序,如果要从数据库或其他资源加载模板,也可以编写自己的加载程序。
注解
请注意,环境的第二个参数是一个选项数组。这个 cache
选项是一个编译缓存目录,Twig在其中缓存已编译的模板,以避免子序列请求的解析阶段。它与您可能要为已计算模板添加的缓存非常不同。对于这种需要,您可以使用任何可用的PHP缓存库。
呈现模板¶
要从Twig环境加载模板,请调用 load()
返回 \Twig\TemplateWrapper
实例:
$template = $twig->load('index.html');
若要使用某些变量呈现模板,请调用 render()
方法:
echo $template->render(['the' => 'variables', 'go' => 'here']);
注解
这个 display()
方法是输出呈现模板的快捷方式。
也可以一次加载和渲染模板:
echo $twig->render('index.html', ['the' => 'variables', 'go' => 'here']);
如果模板定义块,则可以通过 renderBlock()
呼叫:
echo $template->renderBlock('block_name', ['the' => 'variables', 'go' => 'here']);
环境选项¶
创建新的 \Twig\Environment
实例,您可以将一个选项数组作为构造函数第二个参数::
$twig = new \Twig\Environment($loader, ['debug' => true]);
以下选项可用:
debug
boolean当设置为
true
,生成的模板具有__toString()
方法,可用于显示生成的节点(默认为false
)charset
string (defaults toutf-8
)模板使用的字符集。
cache
string orfalse
存储已编译模板的绝对路径,或
false
禁用缓存(这是默认设置)。auto_reload
boolean使用Twig进行开发时,每当源代码发生变化时重新编译模板是很有用的。如果不为
auto_reload
选项,它将根据debug
价值。strict_variables
boolean如果设置为
false
,Twig将自动忽略无效变量(不存在的变量和/或属性/方法),并将它们替换为null
价值观。设置为时true
而是抛出一个默认的Twigfalse
)autoescape
string设置默认的自动转义策略 (
name
,html
,js
,css
,url
,html_attr
,或者一个PHP回调,它接受模板“filename”并返回要使用的转义策略——回调不能是函数名,以避免与内置转义策略冲突);将其设置为false
禁用自动转义。这个name
转义策略根据模板文件名扩展名确定要用于模板的转义策略(此策略在运行时不会产生任何开销,因为自动转义是在编译时完成的)optimizations
integer指示要应用哪些优化的标志(默认为
-1
--已启用所有优化;将其设置为0
禁用)。
装载机¶
加载程序负责从文件系统等资源加载模板。
编译缓存¶
所有模板加载器都可以将编译好的模板缓存到文件系统上,以备将来重用。因为模板只编译一次,所以它可以大大加快Twig的速度。
内置装载机¶
以下是内置装载机的列表:
\Twig\Loader\FilesystemLoader
¶
\Twig\Loader\FilesystemLoader
从文件系统加载模板。此加载程序可以在文件系统的文件夹中找到模板,并且是加载模板的首选方法:
$loader = new \Twig\Loader\FilesystemLoader($templateDir);
它还可以在目录数组中查找模板:
$loader = new \Twig\Loader\FilesystemLoader([$templateDir1, $templateDir2]);
有了这样的配置,Twig将首先在 $templateDir1
如果它们不存在,它将回退到 $templateDir2
.
您可以通过 addPath()
和 prependPath()
方法::
$loader->addPath($templateDir3);
$loader->prependPath($templateDir4);
文件系统加载器还支持名称空间模板。这样可以将模板分组到具有自己模板路径的不同名称空间下。
当使用 setPaths()
, addPath()
和 prependPath()
方法,将命名空间指定为第二个参数(如果未指定,则这些方法作用于“main”命名空间)::
$loader->addPath($templateDir, 'admin');
命名空间模板可以通过 @namespace_name/template_path
符号:
$twig->render('@admin/index.html', []);
\Twig\Loader\FilesystemLoader
支持绝对路径和相对路径。首选使用相对路径,因为它使缓存键独立于项目根目录(例如,它允许从生成服务器预热缓存,该服务器的目录可能与生产服务器上使用的目录不同)::
$loader = new \Twig\Loader\FilesystemLoader('templates', getcwd().'/..');
注解
当不将根路径作为第二个参数传递时,Twig使用 getcwd()
对于相对路径。
\Twig\Loader\ArrayLoader
¶
\Twig\Loader\ArrayLoader
从PHP数组加载模板。向它传递一个绑定到模板名称的字符串数组:
$loader = new \Twig\Loader\ArrayLoader([
'index.html' => 'Hello {{ name }}!',
]);
$twig = new \Twig\Environment($loader);
echo $twig->render('index.html', ['name' => 'Fabien']);
这个装载器对于单元测试非常有用。它还可以用于将所有模板存储在一个PHP文件中的小项目。
小技巧
当使用 Array
使用缓存机制的加载程序,您应该知道,每次模板内容“更改”(缓存键是模板的源代码)时都会生成一个新的缓存键。如果您不想看到您的缓存增长失控,您需要自己清除旧的缓存文件。
\Twig\Loader\ChainLoader
¶
\Twig\Loader\ChainLoader
将模板的加载委托给其他加载程序::
$loader1 = new \Twig\Loader\ArrayLoader([
'base.html' => '{% block content %}{% endblock %}',
]);
$loader2 = new \Twig\Loader\ArrayLoader([
'index.html' => '{% extends "base.html" %}{% block content %}Hello {{ name }}{% endblock %}',
'base.html' => 'Will never be loaded',
]);
$loader = new \Twig\Loader\ChainLoader([$loader1, $loader2]);
$twig = new \Twig\Environment($loader);
在寻找模板时,Twig依次尝试每个加载程序,并在找到模板后立即返回。当渲染 index.html
模板来自上面的示例,Twig将用 $loader2
但是 base.html
模板将从 $loader1
.
注解
您也可以通过 addLoader()
方法。
创建自己的加载程序¶
所有装载机都执行 \Twig\Loader\LoaderInterface
::
interface \Twig\Loader\LoaderInterface
{
/**
* Returns the source context for a given template logical name.
*
* @param string $name The template logical name
*
* @return \Twig\Source
*
* @throws \Twig\Error\LoaderError When $name is not found
*/
public function getSourceContext($name);
/**
* Gets the cache key to use for the cache for a given template name.
*
* @param string $name The name of the template to load
*
* @return string The cache key
*
* @throws \Twig\Error\LoaderError When $name is not found
*/
public function getCacheKey($name);
/**
* Returns true if the template is still fresh.
*
* @param string $name The template name
* @param timestamp $time The last modification time of the cached template
*
* @return bool true if the template is fresh, false otherwise
*
* @throws \Twig\Error\LoaderError When $name is not found
*/
public function isFresh($name, $time);
/**
* Check if we have the source code of a template, given its name.
*
* @param string $name The name of the template to check if we can load
*
* @return bool If the template source code is handled by this loader or not
*/
public function exists($name);
}
这个 isFresh()
方法必须返回 true
如果当前缓存的模板仍然是最新的(给定上次修改时间),或者 false
否则。
这个 getSourceContext()
方法必须返回 \Twig\Source
.
使用扩展名¶
Twig扩展是向Twig添加新特性的包。通过注册扩展名 addExtension()
方法:
$twig->addExtension(new \Twig\Extension\SandboxExtension());
Twig附带以下扩展:
- TwigExtensionCoreExtension :定义Twig的所有核心功能。
- TwigExtensionDebugExtension :定义
dump
函数来帮助调试模板变量。 - TwigExtensionEscaperExtension :添加自动输出转义和转义/取消转义代码块的可能性。
- TwigExtensionSandboxExtension :将沙盒模式添加到默认Twig环境,使评估不受信任的代码变得安全。
- TwigExtensionProfilerExtension :启用内置Twig Profiler。
- TwigExtensionOptimizerExtension :在编译之前优化节点树。
- TwigExtensionStringLoaderExtension :定义
template_from_string
- 函数以允许从模板中的字符串加载模板。
- TwigExtensionStringLoaderExtension :定义
默认情况下,将注册核心、转义器和优化器扩展。
内置扩展¶
本节介绍由内置扩展添加的功能。
小技巧
阅读关于 extending Twig 学习如何创建自己的扩展。
逃逸器扩展¶
这个 escaper
扩展将自动输出转义添加到Twig。它定义了一个标记, autoescape
,和一个过滤器, raw
.
创建转义器扩展时,可以打开或关闭全局输出转义策略::
$escaper = new \Twig\Extension\EscaperExtension('html');
$twig->addExtension($escaper);
如果设置为 html
,模板中的所有变量都被转义(使用 html
逃避策略),除了那些使用 raw
过滤器:
1 | {{ article.to_html|raw }}
|
也可以使用 autoescape
标签:
1 2 3 4 5 | {% autoescape 'html' %}
{{ var }}
{{ var|raw }} {# var won't be escaped #}
{{ var|escape }} {# var won't be double-escaped #}
{% endautoescape %}
|
警告
这个 autoescape
标记对包含的文件没有影响。
转义规则的实现如下:
模板中直接用作变量或筛选器参数的文本(整数、布尔值、数组…)永远不会自动转义:
1 2 3 4
{{ "Twig<br/>" }} {# won't be escaped #} {% set text = "Twig<br/>" %} {{ text }} {# will be escaped #}
结果为文本或标记为安全的变量的表达式永远不会自动转义:
1 2 3 4 5 6 7 8
{{ foo ? "Twig<br/>" : "<br/>Twig" }} {# won't be escaped #} {% set text = "Twig<br/>" %} {{ true ? text : "<br/>Twig" }} {# will be escaped #} {{ false ? text : "<br/>Twig" }} {# won't be escaped #} {% set text = "Twig<br/>" %} {{ foo ? text|raw : "<br/>Twig" }} {# won't be escaped #}
对象与A
__toString
方法转换为字符串并转义。您可以通过将一些类和/或接口标记为对某些策略是安全的EscaperExtension::addSafeClass()
:1 2 3 4 5 6 7 8 9 10 11
// mark object of class Foo as safe for the HTML strategy $escaper->addSafeClass('Foo', ['html']); // mark object of interface Foo as safe for the HTML strategy $escaper->addSafeClass('FooInterface', ['html']); // mark object of class Foo as safe for the HTML and JS strategies $escaper->addSafeClass('Foo', ['html', 'js']); // mark object of class Foo as safe for all strategies $escaper->addSafeClass('Foo', ['all']);
在应用任何其他筛选器之后,在打印之前应用转义:
1
{{ var|upper }} {# is equivalent to {{ var|upper|escape }} #}
这个 raw 过滤器只能在过滤器链的末端使用:
1 2 3
{{ var|raw|upper }} {# will be escaped #} {{ var|upper|raw }} {# won't be escaped #}
如果链中的最后一个筛选器对于当前上下文标记为安全,则不应用自动转义(例如。
html
或js
)escape
和escape('html')
标记为对HTML安全,escape('js')
对JavaScript标记为安全,raw
标记为安全。1 2 3 4 5
{% autoescape 'js' %} {{ var|escape('html') }} {# will be escaped for HTML and JavaScript #} {{ var }} {# will be escaped for JavaScript #} {{ var|escape('js') }} {# won't be double-escaped #} {% endautoescape %}
注解
请注意,自动转义有一些限制,因为转义是在求值后应用于表达式的。例如,在处理连接时, {{{{ foo|raw ~ bar }}}}
不会给出预期的结果,因为转义应用于串联的结果,而不是应用于单个变量(因此 raw
过滤器在这里没有任何效果)。
沙盒扩展¶
这个 sandbox
扩展可用于计算不受信任的代码。禁止访问不安全的属性和方法。沙盒安全性由策略实例管理。默认情况下,Twig附带一个策略类: \Twig\Sandbox\SecurityPolicy
. 此类允许您列出一些标记、筛选器、属性和方法的白名单:
$tags = ['if'];
$filters = ['upper'];
$methods = [
'Article' => ['getTitle', 'getBody'],
];
$properties = [
'Article' => ['title', 'body'],
];
$functions = ['range'];
$policy = new \Twig\Sandbox\SecurityPolicy($tags, $filters, $methods, $properties, $functions);
对于以前的配置,安全策略将只允许使用 if
标签,和 upper
过滤器。而且,模板只能调用 getTitle()
和 getBody()
方法对 Article
对象,以及 title
和 body
公共财产。其他的一切都是不允许的,并且会产生 \Twig\Sandbox\SecurityError
例外。
策略对象是沙盒构造函数的第一个参数:
$sandbox = new \Twig\Extension\SandboxExtension($policy);
$twig->addExtension($sandbox);
默认情况下,沙盒模式是禁用的,当使用 sandbox
标签:
1 2 3 | {% sandbox %}
{% include 'user.html' %}
{% endsandbox %}
|
您可以通过 true
作为扩展构造函数的第二个参数:
$sandbox = new \Twig\Extension\SandboxExtension($policy, true);
探查器扩展¶
这个 profiler
extension为Twig模板启用了一个profiler;它应该只在开发计算机上使用,因为它会增加一些开销:
$profile = new \Twig\Profiler\Profile();
$twig->addExtension(new \Twig\Extension\ProfilerExtension($profile));
$dumper = new \Twig\Profiler\Dumper\TextDumper();
echo $dumper->dump($profile);
配置文件包含有关模板、块和宏执行的时间和内存消耗的信息。
也可以将数据转储到 Blackfire.io 兼容格式:
$dumper = new \Twig\Profiler\Dumper\BlackfireDumper();
file_put_contents('/path/to/profile.prof', $dumper->dump($profile));
上传配置文件使其可视化(创建一个 free account 第一个):
1 | blackfire --slot=7 upload /path/to/profile.prof
|
优化器扩展¶
这个 optimizer
扩展在编译之前优化节点树::
$twig->addExtension(new \Twig\Extension\OptimizerExtension());
默认情况下,将启用所有优化。您可以通过将它们传递给构造函数来选择要启用的:
$optimizer = new \Twig\Extension\OptimizerExtension(\Twig\NodeVisitor\OptimizerNodeVisitor::OPTIMIZE_FOR);
$twig->addExtension($optimizer);
Twig支持以下优化:
\Twig\NodeVisitor\OptimizerNodeVisitor::OPTIMIZE_ALL
,启用所有优化(这是默认值)。\Twig\NodeVisitor\OptimizerNodeVisitor::OPTIMIZE_NONE
,禁用所有优化。但这会增加编译时间,并减少编译所消耗的时间。\Twig\NodeVisitor\OptimizerNodeVisitor::OPTIMIZE_FOR
,优化for
通过移除loop
尽可能创建变量。\Twig\NodeVisitor\OptimizerNodeVisitor::OPTIMIZE_RAW_FILTER
,删除raw
尽可能过滤。\Twig\NodeVisitor\OptimizerNodeVisitor::OPTIMIZE_VAR_ACCESS
,尽可能简化已编译模板中变量的创建和访问。
例外情况¶
Twig可以引发异常:
\Twig\Error\Error
:所有错误的基异常。\Twig\Error\SyntaxError
:抛出以告诉用户模板语法有问题。\Twig\Error\RuntimeError
:在运行时发生错误时抛出(例如,当筛选器不存在时)。\Twig\Error\LoaderError
:在加载模板期间发生错误时引发。\Twig\Sandbox\SecurityError
:在沙盒模板中调用不允许的标记、筛选器或方法时引发。