Twig

灵活、快速且安全的
PHP 模板引擎

a Symfony Product
文档 Twig 模板设计师指南
您正在阅读 Twig 3.x 的文档。切换到 Twig 1.x, 2.x 的文档。

Twig 模板设计师指南

本文档描述了模板引擎的语法和语义,对于创建 Twig 模板的人员来说,它将是最有用的参考。

概要

模板是一个常规文本文件。它可以生成任何基于文本的格式(HTML、XML、CSV、LaTeX 等)。它没有特定的扩展名,.html.xml 都可以。

模板包含变量表达式,它们在模板求值时被替换为值,以及控制模板逻辑的 标签

下面是一个最小的模板,说明了一些基本知识。我们将在后面详细介绍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html>
    <head>
        <title>My Webpage</title>
    </head>
    <body>
        <ul id="navigation">
        {% for item in navigation %}
            <li><a href="{{ item.href }}">{{ item.caption }}</a></li>
        {% endfor %}
        </ul>

        <h1>My Webpage</h1>
        {{ a_variable }}
    </body>
</html>

有两种类型的分隔符:{% ... %}{{ ... }}。第一个用于执行语句,例如 for 循环,后者输出表达式的结果。

提示

要试验 Twig,您可以使用 Twig Playground

第三方集成

许多 IDE 支持 Twig 的语法高亮和自动完成

您可能也对以下内容感兴趣

  • Twig Language Server: 提供一些语言功能,如语法高亮、诊断、自动完成等。
  • TwigQI: 一个扩展,可在编译期间分析您的模板中常见的错误
  • TwigStan: 一个由 PHPStan 驱动的 Twig 模板静态分析器

变量

Twig 模板可以访问 PHP 应用程序提供的变量以及在模板中通过 set 标签创建的变量。这些变量可以在模板中进行操作和显示。

Twig 尝试尽可能地抽象 PHP 类型,并使用一些基本类型,这些类型受 filtersfunctionstests 等支持

Twig 类型 PHP 类型
字符串 字符串或 Stringable 对象
数字 整数或浮点数
布尔值 truefalse
null null
可迭代对象 (映射) 数组
可迭代对象 (序列) 数组
可迭代对象 (对象) 可迭代对象
对象 对象

iterableobject 类型公开了您可以通过点 (.) 运算符访问的属性

1
{{ user.name }}

注意

重要的是要知道花括号 不是 变量的一部分,而是打印语句的一部分。在标签内访问变量时,请勿将花括号括在它们周围。

如果变量或属性不存在,则行为取决于 strict_variables 选项值(请参阅 环境选项

  • false 时,它返回 null
  • true 时,它会抛出异常。

了解更多关于 点运算符 的信息。

全局变量

以下变量始终在模板中可用

  • _self:引用当前模板名称;
  • _context:引用当前上下文;
  • _charset:引用当前字符集。

设置变量

您可以在代码块内为变量赋值。赋值使用 set 标签

1
2
3
{% set name = 'Fabien' %}
{% set numbers = [1, 2] %}
{% set map = {'city': 'Paris'} %}

过滤器

变量和表达式可以通过过滤器进行修改。过滤器通过管道符号 (|) 与变量分隔。可以链接多个过滤器。一个过滤器的输出应用于下一个过滤器。

以下示例从 name 中删除所有 HTML 标签并将其转换为首字母大写

1
{{ name|striptags|title }}

接受参数的过滤器在参数周围带有括号。此示例通过逗号连接列表的元素

1
{{ list|join(', ') }}

要在代码段上应用过滤器,请使用 apply 标签将其包装起来

1
2
3
{% apply upper %}
    This text becomes uppercase
{% endapply %}

转到 过滤器 页面以了解有关内置过滤器的更多信息。

警告

由于 filter 运算符具有最高的 优先级,因此在过滤更“复杂”的表达式时,请使用括号

1
2
3
{{ (1..5)|join(', ') }}

{{ ('HELLO' ~ 'FABIEN')|lower }}

函数

可以调用函数来生成内容。函数通过其名称后跟括号 (()) 调用,并且可能带有参数。

例如,range 函数返回一个包含整数算术级数的列表

1
2
3
{% for i in range(0, 3) %}
    {{ i }},
{% endfor %}

转到 函数 页面以了解有关内置函数的更多信息。

命名参数

在可以传递参数的任何地方都支持命名参数:函数、过滤器、测试、宏和点运算符参数。

3.15

宏和点运算符参数的命名参数是在 Twig 3.15 中添加的。

3.12

Twig 同时支持 =: 作为参数名称和值之间的分隔符,但对 : 的支持是在 Twig 3.12 中引入的。

1
2
3
{% for i in range(low: 1, high: 10, step: 2) %}
    {{ i }},
{% endfor %}

使用命名参数使您的模板更清楚地表达您作为参数传递的值的含义

1
2
3
4
5
{{ data|convert_encoding('UTF-8', 'iso-2022-jp') }}

{# versus #}

{{ data|convert_encoding(from: 'iso-2022-jp', to: 'UTF-8') }}

命名参数还允许您跳过一些您不想更改默认值的参数

1
2
3
4
5
{# the first argument is the date format, which defaults to the global date format if null is passed #}
{{ "now"|date(null, "Europe/Paris") }}

{# or skip the format value by using a named argument for the time zone #}
{{ "now"|date(timezone: "Europe/Paris") }}

您还可以在一个调用中同时使用位置参数和命名参数,在这种情况下,位置参数必须始终位于命名参数之前

1
{{ "now"|date('d/m/Y H:i', timezone: "Europe/Paris") }}

提示

每个函数、过滤器和测试文档页面都有一个部分,其中列出了所有受支持的参数的名称。

控制结构

控制结构是指控制程序流程的所有事物 - 条件语句(即 if/elseif/else)、for 循环以及诸如块之类的事物。控制结构出现在 {% ... %} 块内。

例如,要显示变量 users 中提供的用户列表,请使用 for 标签

1
2
3
4
5
6
<h1>Members</h1>
<ul>
    {% for user in users %}
        <li>{{ user.username|e }}</li>
    {% endfor %}
</ul>

if 标签可用于测试表达式

1
2
3
4
5
6
7
{% if users|length > 0 %}
    <ul>
        {% for user in users %}
            <li>{{ user.username|e }}</li>
        {% endfor %}
    </ul>
{% endif %}

转到 标签 页面以了解有关内置标签的更多信息。

注释

要注释掉模板的一部分,请使用注释语法 {# ... #}。这对于调试或为其他模板设计师或您自己添加信息很有用

1
2
3
4
5
{# note: disabled template because we no longer use this
    {% for user in users %}
        ...
    {% endfor %}
#}

3.15

Twig 3.15 中添加了内联注释。

如果您想在块、变量或注释内添加注释,请使用内联注释。它们以 # 开头,并持续到行尾

1
2
3
4
5
6
7
8
9
10
11
12
13
{{
    # this is an inline comment
    "Hello World"|upper
    # this is an inline comment
}}

{{
    {
        # this is an inline comment
        fruit: 'apple', # this is an inline comment
        color: 'red', # this is an inline comment
    }|join(', ')
}}

内联注释也可以与表达式位于同一行

1
2
3
{{
    "Hello World"|upper # this is an inline comment
}}

由于内联注释持续到当前行末尾,因此以下代码不起作用,因为 }} 将成为注释的一部分

1
{{ "Hello World"|upper # this is an inline comment }}

包含其他模板

include 函数用于包含模板并将该模板的渲染内容返回到当前模板中

1
{{ include('sidebar.html.twig') }}

默认情况下,包含的模板与包含它们的模板具有相同的上下文访问权限。这意味着在主模板中定义的任何变量在包含的模板中也可用

1
2
3
{% for box in boxes %}
    {{ include('render_box.html.twig') }}
{% endfor %}

包含的模板 render_box.html.twig 可以访问 box 变量。

模板的名称取决于模板加载器。例如,\Twig\Loader\FilesystemLoader 允许您通过给出文件名来访问其他模板。您可以使用斜杠访问子目录中的模板

1
{{ include('sections/articles/sidebar.html.twig') }}

此行为取决于嵌入 Twig 的应用程序。

模板继承

Twig 最强大的部分是模板继承。模板继承允许您构建一个基础“骨架”模板,其中包含您站点的所有公共元素,并定义子模板可以覆盖的

从示例开始理解这个概念更容易。

让我们定义一个基本模板 base.html.twig,它定义了一个 HTML 骨架文档,可能用于双列页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html>
    <head>
        {% block head %}
            <link rel="stylesheet" href="style.css"/>
            <title>{% block title %}{% endblock %} - My Webpage</title>
        {% endblock %}
    </head>
    <body>
        <div id="content">{% block content %}{% endblock %}</div>
        <div id="footer">
            {% block footer %}
                &copy; Copyright 2011 by <a href="https://example.com/">you</a>.
            {% endblock %}
        </div>
    </body>
</html>

在此示例中,block 标签定义了子模板可以填充的四个块。block 标签所做的只是告诉模板引擎,子模板可以覆盖模板的这些部分。

子模板可能如下所示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{% extends "base.html.twig" %}

{% block title %}Index{% endblock %}
{% block head %}
    {{ parent() }}
    <style type="text/css">
        .important { color: #336699; }
    </style>
{% endblock %}
{% block content %}
    <h1>Index</h1>
    <p class="important">
        Welcome to my awesome homepage.
    </p>
{% endblock %}

extends 标签是这里的关键。它告诉模板引擎此模板“继承”另一个模板。当模板系统评估此模板时,首先它会找到父模板。extends 标签应该是模板中的第一个标签。

请注意,由于子模板未定义 footer 块,因此使用父模板中的值。

可以通过使用 parent 函数来渲染父块的内容。这将返回父块的结果

1
2
3
4
5
{% block sidebar %}
    <h3>Table Of Contents</h3>
    ...
    {{ parent() }}
{% endblock %}

提示

extends 标签的文档页面描述了更高级的功能,如块嵌套、作用域、动态继承和条件继承。

注意

Twig 还通过 use 标签,借助“水平重用”支持多重继承。

HTML 转义

当从模板生成 HTML 时,总是存在变量包含影响结果 HTML 的字符的风险。有两种方法:手动转义每个变量或默认自动转义所有内容。

Twig 同时支持这两种方法,默认情况下启用自动转义。

自动转义策略可以通过 autoescape 选项进行配置,默认为 html

手动转义

如果启用了手动转义,则 有责任在需要时转义变量。要转义什么?来自不受信任来源的任何变量。

转义通过使用 escapee 过滤器来完成

1
{{ user.username|e }}

默认情况下,escape 过滤器使用 html 策略,但根据转义上下文,您可能需要显式使用另一种策略

1
2
3
4
{{ user.username|e('js') }}
{{ user.username|e('css') }}
{{ user.username|e('url') }}
{{ user.username|e('html_attr') }}

自动转义

无论是否启用自动转义,您都可以使用 autoescape 标签标记要转义或不转义的模板部分

1
2
3
{% autoescape %}
    Everything will be automatically escaped in this block (using the HTML strategy)
{% endautoescape %}

默认情况下,自动转义使用 html 转义策略。如果您在其他上下文中输出变量,则需要使用适当的转义策略显式转义它们

1
2
3
{% autoescape 'js' %}
    Everything will be automatically escaped in this block (using the JS strategy)
{% endautoescape %}

转义

有时希望甚至有必要让 Twig 忽略它原本会作为变量或块处理的部分。例如,如果使用默认语法,并且您想在模板中使用 {{ 作为原始字符串,而不是启动变量,则必须使用技巧。

最简单的方法是使用变量表达式输出变量分隔符 ({{)

1
{{ '{{' }}

对于较大的部分,标记 verbatim 块是有意义的。

宏与常规编程语言中的函数相当。它们对于重用 HTML 片段以避免重复自己很有用。它们在 macro 标签文档中描述。

表达式

Twig 允许在任何地方使用表达式。

字面量

表达式最简单的形式是字面量。字面量是 PHP 类型(如字符串、数字和数组)的表示形式。存在以下字面量

  • "Hello World":两个双引号或单引号之间的所有内容都是字符串。当您需要在模板中使用字符串时,它们很有用(例如,作为函数调用、过滤器的参数,或者只是扩展或包含模板)。

    请注意,某些字符需要转义
    • \f:换页符
    • \n:换行符
    • \r:回车符
    • \t:水平制表符
    • \v:垂直制表符
    • \x:十六进制转义序列
    • \0\377:表示字符的八进制转义序列
    • \:反斜杠

    使用单引号字符串时,单引号字符 (') 需要用反斜杠 (\') 转义。使用双引号字符串时,双引号字符 (") 需要用反斜杠 (\") 转义。

    例如,如果单引号字符串前面有反斜杠 (\),则可以包含分隔符,例如 'It\'s good'。如果字符串包含反斜杠(例如 'c:\Program Files'),请通过将其加倍来转义它(例如 'c:\\Program Files')。

  • 42 / 42.23:整数和浮点数通过写下数字来创建。如果存在点,则该数字为浮点数,否则为整数。下划线可以用作数字分隔符以
    提高可读性(-3_141.592_65 等同于 -3141.59265)。
  • ["first_name", "last_name"]:序列由逗号 (,) 分隔并用方括号 ([]) 包裹的表达式序列定义。
  • {"name": "Fabien"}:映射由逗号 (,) 分隔并用花括号 ({}) 包裹的键和值列表定义

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    {# keys as string #}
    {'name': 'Fabien', 'city': 'Paris'}
    
    {# keys as names (equivalent to the previous mapping) #}
    {name: 'Fabien', city: 'Paris'}
    
    {# keys as integer #}
    {2: 'Twig', 4: 'Symfony'}
    
    {# keys can be omitted if it is the same as the variable name #}
    {Paris}
    {# is equivalent to the following #}
    {'Paris': Paris}
    
    {# keys as expressions (the expression must be enclosed into parentheses) #}
    {% set key = 'name' %}
    {(key): 'Fabien', (1 + 1): 2, ('ci' ~ 'ty'): 'city'}
  • true / falsetrue 表示真值,false 表示假值。
  • nullnull 表示没有特定值。这是变量不存在时返回的值。nonenull 的别名。

序列和映射可以嵌套

1
{% set complex = [1, {"name": "Fabien"}] %}

提示

使用双引号或单引号字符串对性能没有影响,但 字符串插值 仅在双引号字符串中受支持。

字符串插值

字符串插值 (#{expression}) 允许任何有效表达式出现在 双引号字符串 中。评估该表达式的结果将插入到字符串中

1
2
{{ "first #{middle} last" }}
{{ "first #{1 + 2} last" }}

提示

可以通过使用反斜杠 (\) 转义字符串插值来忽略它们

1
2
{# outputs first #{1 + 2} last #}
{{ "first \#{1 + 2} last" }}

数学运算

Twig 允许您在模板中进行数学运算;支持以下运算符

  • +:将两个数字相加(操作数转换为数字)。{{ 1 + 1 }}2
  • -:从第一个数字中减去第二个数字。{{ 3 - 2 }}1
  • /:将两个数字相除。返回的值将是浮点数。{{ 1 / 2 }}{{ 0.5 }}
  • %:计算整数除法的余数。{{ 11 % 7 }}4
  • //:将两个数字相除并返回向下取整的整数结果。{{ 20 // 7 }}2{{ -20 // 7 }}-3(这只是 round 过滤器的语法糖)。
  • *:将左操作数与右操作数相乘。{{ 2 * 2 }} 将返回 4
  • **:将左操作数提升为右操作数的幂。{{ 2 ** 3 }} 将返回 8。请注意,** 运算符是右结合的,这意味着 {{ -1**0 }} 等同于 {{ -(1**0) }} 而不是 {{ (-1)**0 }}

逻辑运算

您可以使用以下运算符组合多个表达式

  • and:如果左操作数和右操作数均为真,则返回 true。
  • xor:如果左操作数或右操作数 之一 为真,但不能两者都为真,则返回 true。
  • or:如果左操作数或右操作数为真,则返回 true。
  • not:否定语句。
  • (expr):对表达式进行分组。

注意

Twig 还支持位运算符(b-andb-xorb-or)。

注意

运算符区分大小写。

比较运算

任何表达式中都支持以下数学比较运算符:==!=<>>=<=

飞船运算符

飞船运算符 (<=>) 用于比较两个表达式。当第一个操作数分别小于、等于或大于第二个操作数时,它返回 -101

注意

PHP 飞船运算符文档 中了解更多信息。

可迭代运算符

检查可迭代对象 has everyhas some 的元素是否返回 true,使用箭头函数。箭头函数接收可迭代对象的值作为其参数

1
2
3
4
5
6
7
{% set sizes = [34, 36, 38, 40, 42] %}

{% set hasOnlyOver38 = sizes has every v => v > 38 %}
{# hasOnlyOver38 is false #}

{% set hasOver38 = sizes has some v => v > 38 %}
{# hasOver38 is true #}

对于空的可迭代对象,has every 返回 true,而 has some 返回 false

包含运算符

in 运算符执行包含测试。如果左操作数包含在右操作数中,则返回 true

1
2
3
4
5
{# returns true #}

{{ 1 in [1, 2, 3] }}

{{ 'cd' in 'abcde' }}

提示

您可以使用此运算符对字符串、序列、映射或实现 Traversable 接口的对象执行包含测试。

要执行否定测试,请使用 not in 运算符

1
2
3
4
{% if 1 not in [1, 2, 3] %}

{# is equivalent to #}
{% if not (1 in [1, 2, 3]) %}

starts withends with 运算符用于检查字符串是否以给定的子字符串开头或结尾

1
2
3
4
5
{% if 'Fabien' starts with 'F' %}
{% endif %}

{% if 'Fabien' ends with 'n' %}
{% endif %}

注意

对于复杂的字符串比较,matches 运算符允许您使用 正则表达式

1
2
{% if phone matches '/^[\\d\\.]+$/' %}
{% endif %}

测试运算符

is 运算符执行测试。测试可用于针对常见表达式测试变量。右操作数是测试的名称

1
2
3
{# find out if a variable is odd #}

{{ name is odd }}

测试也可以接受参数

1
{% if post.status is constant('Post::PUBLISHED') %}

可以通过使用 is not 运算符来否定测试

1
2
3
4
{% if post.status is not constant('Post::PUBLISHED') %}

{# is equivalent to #}
{% if not (post.status is constant('Post::PUBLISHED')) %}

转到 测试 页面以了解有关内置测试的更多信息。

其他运算符

以下运算符不属于任何其他类别

  • |:应用过滤器。
  • ..:基于运算符之前和之后的运算数创建序列(这是 range 函数的语法糖)

    1
    2
    3
    4
    {% for i in 1..5 %}{{ i }}{% endfor %}
    
    {# is equivalent to #}
    {% for i in range(1, 5) %}{{ i }}{% endfor %}

    请注意,由于 运算符优先级规则,当将其与过滤器运算符组合时,必须使用括号

    1
    {{ (1..5)|join(', ') }}
  • ~:将所有操作数转换为字符串并将它们连接起来。{{ "Hello " ~ name ~ "!" }} 将返回(假设 name'John'Hello John!
  • ., []:获取变量的属性。

    (.) 运算符抽象了获取变量的属性(PHP 对象的方法、属性或常量,或 PHP 数组的项)

    1
    2
    3
    4
    {{ user.name }}
    
    Twig supports a specific syntax via the ``[]`` operator for accessing items
    on sequences and mappings, like in ``user['name']``:

    . 之后,您可以通过用括号 () 将其包装起来来使用任何表达式。

    一种用例是当属性包含特殊字符时(例如 -,它将被解释为减号运算符)

    1
    2
    {# equivalent to the non-working user.first-name #}
    {{ user.('first-name') }}

    另一种用例是当属性是“动态的”(通过变量定义)时

    1
    2
    {{ user.(name) }}
    {{ user.('get' ~ name) }}

    在 Twig 3.15 之前,对于之前的两个用例,请改用 attribute 函数。

    Twig 通过 [] 运算符支持特定语法,用于访问序列和映射上的项

    1
    {{ user['name'] }}

    调用方法时,可以使用 () 运算符传递参数

    1
    2
    3
    4
    {{ html.generate_input() }}
    {{ html.generate_input('pwd', 'password') }}
    {# or using named arguments #}
    {{ html.generate_input(name: 'pwd', type: 'password') }}

    为了将 user.name 解析为 PHP 调用,Twig 在运行时使用以下算法

    • 检查 user 是否是 PHP 数组或 ArrayObject/ArrayAccess 对象,以及 name 是否是有效元素;
    • 如果不是,并且如果 user 是 PHP 对象,请检查 name 是否是有效属性;
    • 如果不是,并且如果 user 是 PHP 对象,请检查 name 是否是类常量;
    • 如果不是,并且如果 user 是 PHP 对象,请检查以下方法并调用第一个有效方法:name()getName()isName()hasName()
    • 如果不是,并且如果 strict_variablesfalse,则返回 null
    • 如果不是,则抛出异常。

    为了将 user['name'] 解析为 PHP 调用,Twig 在运行时使用以下算法

    • 检查 user 是否是数组,以及 name 是否是有效元素;
    • 如果不是,并且如果 strict_variablesfalse,则返回 null
    • 如果不是,则抛出异常。

    Twig 通过 () 运算符支持特定语法,用于调用对象上的方法,例如 user.name()

    • 检查 user 是否是对象,并且是否具有 name()getName()isName()hasName() 方法;
    • 如果不是,并且如果 strict_variablesfalse,则返回 null
    • 如果不是,则抛出异常。
  • ?::三元运算符

    1
    2
    3
    {{ result ? 'yes' : 'no' }}
    {{ result ?: 'no' }} is the same as {{ result ? result : 'no' }}
    {{ result ? 'yes' }} is the same as {{ result ? 'yes' : '' }}
  • ??:null 合并运算符

    1
    2
    {# returns the value of result if it is defined and not null, 'no' otherwise #}
    {{ result ?? 'no' }}
  • ...:展开运算符可用于展开序列或映射,或展开函数调用的参数

    1
    2
    3
    4
    {% set numbers = [1, 2, ...moreNumbers] %}
    {% set ratings = {'q1': 10, 'q2': 5, ...moreRatings} %}
    
    {{ 'Hello %s %s!'|format(...['Fabien', 'Potencier']) }}

    3.15

    对展开函数调用的参数的支持是在 Twig 3.15 中引入的。

  • =>:箭头运算符允许创建函数。函数由参数(使用括号表示多个参数)和一个箭头 (=>) 后跟要执行的表达式组成。表达式可以访问所有传递的参数。箭头函数作为过滤器、函数、测试、宏和方法调用的参数受支持。

    例如,内置的 mapreducesortfilterfind 过滤器接受箭头函数作为参数

    1
    {{ people|map(p => p.first_name)|join(', ') }}

    箭头函数可以存储在变量中

    1
    2
    3
    {% set first_name_fn = (p) => p.first_name %}
    
    {{ people|map(first_name_fn)|join(', ') }}

    3.15

    Twig 3.15 中添加了对函数、宏和方法调用的箭头函数支持(过滤器和测试已经受支持)。

    可以使用 invoke 过滤器调用箭头函数。

    3.19

    invoke 过滤器已在 Twig 3.19 中添加。

运算符

Twig 使用运算符在模板中执行各种操作。理解这些运算符的优先级对于编写正确且高效的 Twig 模板至关重要。

运算符优先级规则如下,优先级最低的运算符首先列出。

优先级 运算符 类型 结合性 描述
512 ... prefix n/a 展开运算符
=> 300 | infix Twig 过滤器调用
  (     Twig 函数调用
  .     获取变量的属性
  [     数组访问
500 - prefix n/a  
  +      
300 => 5 ?? infix Null 合并运算符 (a ?? b)
250 => infix 箭头函数 (x => expr)
200 ** infix 指数运算符
100 is infix Twig 测试
  is not     Twig 测试
60 * infix  
  /      
  //     向下取整除法
  %      
50 => 70 not prefix n/a  
40 => 27 ~ infix  
30 + infix  
  -      
25 .. infix  
20 == infix  
  !=      
  <=>      
  <      
  >      
  >=      
  <=      
  not in      
  in      
  matches      
  starts with      
  ends with      
  has some      
  has every      
18 b-and infix  
17 b-xor infix  
16 b-or infix  
15 and infix  
12 xor infix  
10 or infix  
5 ?: infix Elvis 运算符 (a ?: b)
  ?:     Elvis 运算符 (a ?: b)
0 ( prefix n/a 显式分组表达式 (a)
  literal     字面量值(布尔值、字符串、数字、序列、映射等)
  ? infix 条件运算符 (a ? b : c)

当优先级在 4.0 中更改时,新优先级由箭头 => 指示。

这是 Twig 4.0 的相同表格,其中调整了优先级

优先级 运算符 类型 结合性 描述
512 ... prefix n/a 展开运算符
  ( infix Twig 函数调用
  .     获取变量的属性
  [     数组访问
500 - prefix n/a  
  +      
300 | infix Twig 过滤器调用
250 => infix 箭头函数 (x => expr)
200 ** infix 指数运算符
100 is infix Twig 测试
  is not     Twig 测试
70 not prefix n/a  
60 * infix  
  /      
  //     向下取整除法
  %      
30 + infix  
  -      
27 ~ infix  
25 .. infix  
20 == infix  
  !=      
  <=>      
  <      
  >      
  >=      
  <=      
  not in      
  in      
  matches      
  starts with      
  ends with      
  has some      
  has every      
18 b-and infix  
17 b-xor infix  
16 b-or infix  
15 and infix  
12 xor infix  
10 or infix  
5 ?? infix Null 合并运算符 (a ?? b)
  ?:     Elvis 运算符 (a ?: b)
  ?:     Elvis 运算符 (a ?: b)
0 ( prefix n/a 显式分组表达式 (a)
  literal     字面量值(布尔值、字符串、数字、序列、映射等)
  ? infix 条件运算符 (a ? b : c)

在不使用任何括号的情况下,运算符优先级规则用于确定如何将代码转换为 PHP

1
2
3
{{ 6 b-and 2 or 6 b-and 16 }}

{# it is converted to the following PHP code: (6 & 2) || (6 & 16) #}

通过使用括号显式分组表达式来更改默认优先级

1
2
3
4
5
6
7
{% set greeting = 'Hello ' %}
{% set name = 'Fabien' %}

{{ greeting ~ name|lower }}   {# Hello fabien #}

{# use parenthesis to change precedence #}
{{ (greeting ~ name)|lower }} {# hello fabien #}

空白控制

模板标签后的第一个换行符会被自动移除(类似于 PHP)。模板引擎不会进一步修改空白字符,因此每个空白字符(空格、制表符、换行符等)都会保持不变地返回。

你也可以在每个标签级别控制空白字符。通过在标签上使用空白字符控制修饰符,你可以修剪前导或尾随空白字符。

Twig 支持两种修饰符

  • 空白字符修剪 通过 - 修饰符:移除所有空白字符(包括换行符);
  • 行空白字符修剪 通过 ~ 修饰符:移除所有空白字符(不包括换行符)。在右侧使用此修饰符会禁用从 PHP 继承的默认移除第一个换行符的行为。

修饰符可以用于标签的任一侧,例如 {%--%},它们会消耗标签该侧的所有空白字符。可以在标签的一侧或两侧使用修饰符。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{% set value = 'no spaces' %}
{#- No leading/trailing whitespace -#}
{%- if true -%}
    {{- value -}}
{%- endif -%}
{# output 'no spaces' #}

<li>
    {{ value }}    </li>
{# outputs '<li>\n    no spaces    </li>' #}

<li>
    {{- value }}    </li>
{# outputs '<li>no spaces    </li>' #}

<li>
    {{~ value }}    </li>
{# outputs '<li>\nno spaces    </li>' #}

扩展

Twig 可以被扩展。如果你想创建自己的扩展,请阅读 创建扩展 章节。