# Twig for 开发者

> 原文：[Twig for Developers](https://twig.sensiolabs.org/doc/2.x/api.html)\
> 翻译：小虾米（QQ:509129）

## Twig for 开发者

本章描述了Twig的API，而不是模板语言。这将是最有用的参考对于那些实现模板接口的用户来说，而不是那些创建Twig模板的人来说。

### 基础知识(Basics)

Twig使用一个名为环境(**environment**)的中心对象(类Twig\_Environment)。该类的实例用于存储配置和扩展，用于从文件系统或其他位置加载模板。

大多数应用程序将在应用程序初始化时创建一个Twig\_Environment对象，并将其用于加载模板。在某些情况下，如果使用不同的配置，那么有多个环境并排使用是非常有用的。

配置Twig到加载模板的最简单方法是这样的:

```php
require_once '/path/to/vendor/autoload.php';

$loader = new Twig_Loader_Filesystem('/path/to/templates');
$twig = new Twig_Environment($loader, array(
    'cache' => '/path/to/compilation_cache',
));
```

这将创建一个带有默认设置的模板环境和一个加载器，它会查找/ path / to / templates /文件夹中的模板。不同的加载器是可用的，如果想从数据库或其他资源加载模板，也可以编写自己的文件。

> 注意，环境(**environment**)的第二个参数是一系列选项。缓存选项是一个编译缓存目录，其中Twig缓存已编译的模板，以避免对次序列请求的解析阶段。它与您可能想要为评估的模板添加的缓存非常不同。对于这样的需求，您可以使用任何可用的PHP缓存库。

### 渲染模板(Rendering Templates)

要从Twig环境中加载模板，请调用load()方法，该方法返回Twig\_TemplateWrapper实例:

```php
$template = $twig->load('index.html');
```

要使用一些变量来呈现模板，请调用render()方法:

```php
echo $template->render(array('the' => 'variables', 'go' => 'here'));
```

> display()方法是直接输出模板的快捷方式。

您还可以加载并呈现模板一次搞定:

```php
echo $twig->render('index.html', array('the' => 'variables', 'go' => 'here'));
```

如果模板定义了块，则可以通过renderBlock()调用来单独呈现它们:

```php
echo $template->renderBlock('block_name', array('the' => 'variables', 'go' => 'here'));
```

### 环境选项(Environment Options)

当创建一个新的Twig\_Environment实例时，可以将一系列选项作为构造函数的第二个参数:

```php
$twig = new Twig_Environment($loader, array('debug' => true));
```

以下选项可供选择:

* debug 布尔类&#x578B;_(boolean)_

当设置为true时，生成的模板有一个\_\_toString()方法，您可以使用它来显示生成的节点(默认为false)。

* charset 字符串类型(string)(默认为utf-8)

用于生成模板的基础模板类。

* cache 字符串类型(string) 或 false

一个绝对路径，用于存储已编译的模板，或者是false来禁用缓存(这是默认的)。

* auto\_reload 布尔类&#x578B;_(boolean)_

当使用Twig进行开发时，每当源代码发生变化时重新编译模板是很有用的。如果您不为auto\_reload选项提供一个值，那么它将根据调试值自动确定。

* strict\_variables 布尔类&#x578B;_(boolean)_

如果设置为false,Twig将静默地忽略无效的变量(不存在的变量和属性/方法)，并以null值替换它们。当设置为true时，Twig会抛出一个异常(默认为false)。

* autoescape 字符串类型(string)

设置默认的自动转义策略(名称、html、js、css、url、html\_attr，或一个PHP回调，它接受模板“文件名”并返回转义策略的使用——回调不能是一个函数名，以避免与内置的转义策略发生冲突);设置为false来禁用自动转义。名称逃逸策略决定了基于模板文件名扩展的模板的转义策略(这一策略不会在运行时造成任何开销，因为自动转义是在编译时完成的)。

* optimizations 整型类型(integer)

一个标志(默认为- 1)的标志(默认为- 1)，所有的优化都被启用;将其设置为0来禁用。

### 加载器(Loaders)

加载程序负责从资源(如文件系统)加载模板。

#### 编译缓存(Compilation Cache)

所有模板加载器都可以在文件系统上缓存已编译的模板，以备将来重用。它加速了Twig的速度，因为模板只编译一次;如果使用APC这样的PHP加速器，性能的提升就会更大。请参阅上面的缓存和auto\_reload选项以获得更多信息。

#### 内置的加载器(Built-in Loaders)

下面是内置的loaders Twig提供的列表:

Twig\_Loader\_Filesystem

Twig\_Loader\_Filesystem从文件系统加载模板。这个加载器可以在文件系统的文件夹中找到模板，并且是加载它们的首选方法:

```php
$loader = new Twig_Loader_Filesystem($templateDir);
```

它还可以在一系列目录中寻找模板:

```php
$loader = new Twig_Loader_Filesystem(array($templateDir1, $templateDir2));
```

有了这样的配置，Twig将首先在$ templateDir1中寻找模板，如果它们不存在，那么它就会在$ templateDir2中寻找它们。

您可以通过addPath()和prependPath()方法添加或prepend路径:

```php
$loader->addPath($templateDir3);
$loader->prependPath($templateDir4);
```

文件系统加载器还支持名称空间模板。这允许在有自己的模板路径的不同名称空间中对模板进行分组。

当使用setpath()、addPath()和prependPath()方法时，将名称空间指定为第二个参数(当未指定时，这些方法将在“main”命名空间上执行):

```php
$loader->addPath($templateDir, 'admin');
```

名称空间模板可以通过特殊的@ namespace\_name / template\_path符号来访问:

```php
$twig->render('@admin/index.html', array());
```

Twig\_Loader\_Filesystem支持绝对和相对路径。使用相对路径是首选的，因为它使缓存键独立于项目根目录(例如，它允许从构建服务器中缓存缓存，其中目录可能与生产服务器上使用的目录不同):

```php
$loader = new Twig_Loader_Filesystem('templates', getcwd().'/..');
```

> 当没有将根路径作为第二个参数传递时，Twig会使用getcwd()相对路径。

Twig\_Loader\_Array

Twig\_Loader\_Array从一个PHP数组加载一个模板。它传递了绑定到模板名称的字符串数组:

```php
$loader = new Twig_Loader_Array(array(
    'index.html' => 'Hello {{ name }}!',
));
$twig = new Twig_Environment($loader);

echo $twig->render('index.html', array('name' => 'Fabien'));
```

这个加载器对于单元测试非常有用。它还可以用于小型项目，其中将所有模板存储在一个PHP文件中可能是有意义的。

当使用带有缓存机制的数组加载程序时，您应该知道每当模板内容“变化”(缓存键是模板的源代码)时，都会生成一个新的缓存键。如果您不想看到缓存失控，您需要自己处理旧的缓存文件。

wig\_Loader\_Chain

Twig\_Loader\_Chain将模板加载到其他加载器:

```php
$loader1 = new Twig_Loader_Array(array(
    'base.html' => '{% block content %}{% endblock %}',
));
$loader2 = new Twig_Loader_Array(array(
    'index.html' => '{% extends "base.html" %}{% block content %}Hello {{ name }}{% endblock %}',
    'base.html'  => 'Will never be loaded',
));

$loader = new Twig_Loader_Chain(array($loader1, $loader2));

$twig = new Twig_Environment($loader);
```

在寻找模板时，Twig会依次尝试每个加载器，一旦找到模板，它就会返回。当呈现来自上面例子中的index.htm模板，Twig将用$ loader2加载它，但是base.html模板将从$ loader1加载。

Twig\_Loader\_Chain接受任何实现Twig\_LoaderInterface的加载器。

> 还可以通过addLoader()方法添加loaders。

#### 创建自己的加载器

所有加载器都实现Twig\_LoaderInterface:

```php
interface Twig_LoaderInterface
{
    /**
     * Returns the source context for a given template logical name.
     *
     * @param string $name The template logical name
     *
     * @return Twig_Source
     *
     * @throws Twig_Error_Loader 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_Loader 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_Loader 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。

getSourceContext()方法必须返回Twig\_Source的一个实例。

### 使用扩展(Using Extensions)

Twig扩展是将新特性添加到Twig的包。使用扩展很简单就是使用addExtension()方法:

```php
$twig->addExtension(new Twig_Extension_Sandbox());
```

Twig与以下扩展捆绑在一起:

* Twig\_Extension\_Core:定义Twig的所有核心特性。
* Twig\_Extension\_Escaper:添加自动输出-转义，以及避免/无法避免代码块的可能性。
* Twig\_Extension\_Sandbox:将沙箱模式添加到默认的Twig环境中，从而安全评估不受信任的代码。
* Twig\_Extension\_Profiler:启用了内置的Twig分析器。
* twig\_extension\_优化:在编译之前优化节点树。

核心、逃避者和优化器扩展不需要添加到Twig环境中，因为它们是默认注册的。

内置扩展(Built-in Extensions)

本节描述内置扩展添加的特性。

> 阅读关于扩展Twig的章节，了解如何创建自己的扩展。

#### 核心扩展(Core Extension)

核心扩展定义了Twig的所有核心特性:

* [Tags](https://twig.sensiolabs.org/doc/2.x/tags/index.html)
* [Filters](https://twig.sensiolabs.org/doc/2.x/filters/index.html)
* [Functions](https://twig.sensiolabs.org/doc/2.x/functions/index.html)
* [Tests](https://twig.sensiolabs.org/doc/2.x/tests/index.html)

#### 转义扩展(Escaper Extension)

转义扩展增加了自动输出转义到Twig。它定义了一个标签、autoescape和一个过滤器，raw。

在创建转义扩展时，您可以打开或关闭全局输出转义策略:

```php
$escaper = new Twig_Extension_Escaper('html');
$twig->addExtension($escaper);
```

如果设置为html，模板中的所有变量都可以通过(使用html转义策略)，除非使用raw过滤器:

```php
{{ article.to_html|raw }}
```

您还可以使用自动转义标签改变本地的转义模式:

```php
{% autoescape 'html' %}
    {{ var }}
    {{ var|raw }}      {# var won't be escaped #}
    {{ var|escape }}   {# var won't be double-escaped #}
{% endautoescape %}
```

> autoescape标签对包含的文件没有影响。

转义规则执行如下:

* 直接在模板中使用的文本(整数、布尔值、数组等)不会自动转义:

```php
{{ "Twig<br />" }} {# won't be escaped #}

{% set text = "Twig<br />" %}
{{ text }} {# will be escaped #}
```

* 结果永远是文字或有标记的安全的表达式不会自动转义:

```
{{ foo ? "Twig<br />" : "<br />Twig" }} {# won't be escaped #}

{% set text = "Twig<br />" %}
{{ foo ? text : "<br />Twig" }} {# will be escaped #}

{% set text = "Twig<br />" %}
{{ foo ? text|raw : "<br />Twig" }} {# won't be escaped #}

{% set text = "Twig<br />" %}
{{ foo ? text|escape : "<br />Twig" }} {# the result of the expression won't be escaped #}
```

* 在打印之前，在其他过滤器被应用后，转义被应用:

```markup
{{ var|upper }} {# is equivalent to {{ var|upper|escape }} #}
```

* raw过滤器只能在过滤器链的末端使用:

```
{{ var|raw|upper }} {# will be escaped #}

{{ var|upper|raw }} {# won't be escaped #}
```

如果链中的最后一个过滤器对于当前上下文(例如html或js)是安全的，则不应用自动转义。escape和escape(“html”)标记为安全的html,escape(“js”)在JavaScript上是安全的，raw是安全的。

```markup
{% 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 Extension)

可以使用sandbox扩展来评估不受信任的代码。禁止使用不安全的属性和方法。沙箱安全性由策略实例管理。默认情况下，Twig附带一个策略类:Twig\_Sandbox\_SecurityPolicy。这个类允许你列出一些标签、过滤器、属性和方法:

```php
$tags = array('if');
$filters = array('upper');
$methods = array(
    'Article' => array('getTitle', 'getBody'),
);
$properties = array(
    'Article' => array('title', 'body'),
);
$functions = array('range');
$policy = new Twig_Sandbox_SecurityPolicy($tags, $filters, $methods, $properties, $functions);
```

使用前一个配置，安全策略只允许使用if标记和上过滤器。此外，模板只能调用getTitle()和getBody()方法在文章对象上，以及标题和主体公共属性。其他的都不允许，并生成Twig\_Sandbox\_SecurityError异常。

策略对象是sandbox构造函数的第一个参数:

```php
$sandbox = new Twig_Extension_Sandbox($policy);
$twig->addExtension($sandbox);
```

默认情况下，sandbox模式是禁用的，当使用sandbox标记包含不受信任的模板代码时，应该启用这个模式:

```markup
{% sandbox %}
    {% include 'user.html' %}
{% endsandbox %}
```

您可以将所有模板都通过true作为扩展构造函数的第二个参数:

```php
$sandbox = new Twig_Extension_Sandbox($policy, true);
```

#### 分析器扩展(Profiler Extension)

profiler扩展允许对Twig模板进行分析器;它应该只在您的开发机器上使用，因为它增加了一些开销:

```php
$profile = new Twig_Profiler_Profile();
$twig->addExtension(new Twig_Extension_Profiler($profile));

$dumper = new Twig_Profiler_Dumper_Text();
echo $dumper->dump($profile);
```

一个配置文件包含用于模板、块和宏执行的时间和内存消耗信息。

您还可以将数据转储到[Blackfire.io](https://blackfire.io/)兼容的格式:

```php
$dumper = new Twig_Profiler_Dumper_Blackfire();
file_put_contents('/path/to/profile.prof', $dumper->dump($profile));
```

上传资料，以使其可视化(先创建一个[免费帐户](https://blackfire.io/signup)):

```php
blackfire --slot=7 upload /path/to/profile.prof
```

#### 优化器扩展(Optimizer Extension)

优化器扩展在编译之前优化节点树:

```php
$twig->addExtension(new Twig_Extension_Optimizer());
```

默认情况下，所有的优化都是打开的。您可以通过将它们传递给构造函数来选择要启用的函数:

```php
$optimizer = new Twig_Extension_Optimizer(Twig_NodeVisitor_Optimizer::OPTIMIZE_FOR);

$twig->addExtension($optimizer);
```

Twig支持以下优化:

* Twig\_NodeVisitor\_Optimizer::OPTIMIZE\_ALL，启用所有优化(这是默认值)。
* Twig\_NodeVisitor\_Optimizer::OPTIMIZE\_NONE,禁用所有优化。这减少了编译时间，但是它可以增加执行时间和内存。
* Twig\_NodeVisitor\_Optimizer::OPTIMIZE\_FOR，在可能的情况下，通过移除循环变量的创建来优化for标记。
* Twig\_NodeVisitor\_Optimizer::OPTIMIZE\_RAW\_FILTER，尽可能删除raw过滤器。
* Twig\_NodeVisitor\_Optimizer::OPTIMIZE\_VAR\_ACCESS，可以在可能的情况下简化编译时模板中的变量的创建和访问。

#### 异常(Exceptions)

Twig可以抛出异常:

* Twig\_Error:所有错误的基本异常。
* Twig\_Error\_Syntax:抛出来告诉用户模板语法有问题。
* Twig\_Error\_Runtime:当运行时发生错误时抛出(例如，当一个过滤器不存在时)。
* Twig\_Error\_Loader:在模板加载过程中抛出错误。
* Twig\_Sandbox\_SecurityError:当一个不允许的标记、过滤器或方法被调用在一个沙盒模板中时抛出。
