番外篇:原生twig模板引擎详解(上集:设计师篇)

原生twig模板引擎详解(上集:设计师篇)

 

前文:本文是《云客drupal源码分析》系列的番外篇,由于drupal采用了twig模板引擎,因此该篇将详细介绍twig,但不会涉及drupal任何内容,是原生twig的使用详解,分上下两集,上集供设计师阅读,讲解在模板中的使用,下集供php程序开发人员阅读,讲解程序调用、扩展开发。

 

本篇为上集,额外介绍了安装等必要内容,以便首次接触人员查阅,纯模板设计师可以跳过。

官网地址:https://twig.symfony.com/

本文写作时官网已经发布了V1.35.3 V2.4.8

 

安装:

需求:

php一样,发布大版本后,以前的版本依然会维护一段时间,因此twig目前有两个版本都在维护

1.X版本:至少PHP 5.2.7,从1.34开始至少需要PHP 5.3.3.

2.X版本:至少PHP 7.0.0

 

包括drupal8在内,许多项目都还在使用1.X,这里以1.X做主要介绍,有多种方法安装twig,官方推荐使用composer,运行如下命令即可:

composer require twig/twig:~1.0

为了提高性能twig还提供了有限功能的php层面的C扩展,详见官网,这里我们以下载文件方式来安装。

 

安装:

到这里下载文件包:https://github.com/twigphp/Twig/tags

本文选择: v1.35.3  解压下载的Twig-1.35.3.tar.gz  由于twig使用psr-0的自动加载方式,所以里面的lib就是我们需要的库文件,将其复制到网站根目录即可

你可以在本机通过phpstudy等软件安装运行环境,这里以C:\root\twigtest作为网站根目录,以http://www.twigtest.com/作为域名

根目录建立index.php,内容如下:

<?php

require_once 'lib/Twig/Autoloader.php';

Twig_Autoloader::register();

$loader = new Twig_Loader_Array(array(

    'index' => 'Hello {{ name }}!',

));

$twig = new Twig_Environment($loader);

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

访问域名,即可看到结果,安装完成。

 

开始使用:

假设你已经按前一步设置好了目录与文件,我们来从文件系统加载一个模板文件,进行显示:

在根目录建立子目录“templates”用以存放模板文件,在其中建立文本文件“index.html.twig”,内容如下:

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>twig</title>

</head>

<body>

hello world ! {{name}}

</body>

</html>

在网站根目录重新建立index.php,内容如下:

<?php

require_once 'lib/Twig/Autoloader.php';

Twig_Autoloader::register();


$loader = new Twig_Loader_Filesystem('templates');

$twig = new Twig_Environment($loader, array(

    'cache' => 'templates_cache',

));

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

 

然后访问站点http://www.twigtest.com/index.php,你将会看到:

hello world ! yunke

同时在站点根目录下多出了一个子目录:

templates_cache

其中存放着为提高性能编译为php文件的模板文件,默认只编译一次,如原文件发生变化需重新编译(删除缓存)

 

在以上代码中Twig_Environmenttwig的中枢对象,类接收两个参数:

\Twig_Environment::__construct (Twig_LoaderInterface $loader = null, $options = array())

$loader是实现了\Twig_LoaderInterface接口的加载器,用于加载模板文件

$options是选项数组,控制twig行为,有效选项如下:

debug是否处于调试模式,布尔值,默认为false

charset模板使用的字符编码,默认为 UTF-8

base_template_class基础模板类,用于被编译后的模板php文件,默认为Twig_Template

cache可选值有储存编译后模板的目录,或者为false以禁用编译缓存,这是默认值,也可以是缓存对象(接口:Twig_CacheInterface的实例,见开发者篇)

auto_reload布尔值,在原模板文件改变时是否重新加载,如果没有提供那么将根据debug选项决定

strict_variables是否使用严格变量模式,默认为false,为真时模板中使用无效变量将抛出错误,否则为NULL

autoescape是否全局自动转义,可能的值有:false(禁止转义),true(默认值,等效为html),html(转义html实体),js(转义js),css(转义css),url(转义url),html_attr(转义html和属性),name(基于模板扩展名设置自动转义策略),PHP callback(由一个php回调来返回转义策略,该回调接收模板的名字做参数)

optimizations模板编译时的优化选项,“-1”代表开启全部优化(默认值),“0”代表禁用优化,还有其他值详见下集中优化扩展一节

 

渲染代码:$twig->render('index.html.twig', array('name' => 'yunke'));原型为:

render($name, array $context = array())

第一个参数是模板的文件名,用于加载模板

第二个是传递给模板的变量数组,键名为在模板中的变量名,键值为对应的变量值,该变量数组称为模板的“上下文”,在模板中通过“_context”能访问到该数组,下文将多次提到“上下文”就是指该变量数组

 

模板文件命名:

twig模板是一个段文本内容,可以存放在数据库、php变量、文件等地方,如果是文本文件,命名是任意的,任意扩展名均可,但通常使用“.twig”或“.html.twig”作为扩展名

----上集部分(设计师篇)----

默认界定符:

{% ... %} 执行标签,用于执行语句,如控制结构

{{ ... }} 打印标签,用于打印表达式的计算结果

{# ... #} 注释标签,用于注释,类似程序中的注释:/* ..*/

#{…} 插值标签,用于向表达式中的字符串插入变量值

这些定界符只是twig的默认值,是可以完全自定义的,详见下集开发者篇

 

字面量Literals

字符串:如"Hello World",可用“\”转义特殊字符,如'It\'s good''c:\\Program Files'

 

数字:包括整数和浮点数,如4/3.14

 

数组:如["foo", "bar"],和php不同,不存在键名,她是一个简单的数字索引数组,可嵌套。如:

{% set a = ["one", ["two", "three"]] %}

要想输出“three”可这样访问:{{ a[1][1] }},注意采用点号语法时不能这样:{{ a.1.1 }},而要这样:{{ (a.1).1 }},这有点违反直觉

 

哈希表:等效于php的关联数组,如:{% set a = { 'foo': 'vfoo', 'bar': 'vbar' } %},键值可以是字面量、变量或表达式,其中键名也可以不用引号,不要引号时,并不等于键名采用了一个变量,这有点违反直觉,请看代码:

{% set foo = "yunke" %}

{% set a = { foo: 'vfoo', 'bar': 'vbar' } %}

{{ a.yunke }}

这将不会有任何输出,foo并不被认为是变量,而是字面量,要想输出'vfoo'应该使用{{ a.foo }},如果要想将foo当做变量看待,那么需要为其加上括号,如下:

{% set foo = "yunke" %}

{% set a = { (foo): 'vfoo', 'bar': 'vbar' } %}

{{ a.yunke }}

此时就可以输出'vfoo'了, 加括号实际是采用了表达式键名,此时还可以这样:
 

{% set foo = 'foo' %}

{ (foo): 'foo', (1 + 1): 'bar', (foo ~ 'b'): 'baz' }

数组和哈希表可以混合使用,且可以嵌套

 

布尔值:true / false,没有引号

 

空值:null,代表值不存在,它有个别名:none

 

访问变量内容:

{{yunke}}

直接显示变量“yunke”的内容,界定符内可以有空格,如{{  yunke  }} ,下同

 

{{yunke.name}}

用点号可以访问对象的属性或数组的元素,这里“yunke”可以是对象也可以是数组,name是属性名或数组键名

 

{{yunke[‘name’]}}

也可以用下标,但不能用于对象,此时“yunke”只能是数组

 

{{ attribute(foo, 'data-bar') }}

如果属性名中包含特殊字符时可以使用属性函数,如“-”可能和减号混淆,属性函数可明确语义

 

如果变量不存在,将得到一个NULL值(在显示上什么也没有),如果选项中“strict_variables”值为真,那么将抛出错误,在内部点号“.”方式实际是执行以下逻辑,以foo.bar为列:

1、检查foo是否是一个数组且bar是其的有效键名,如果是则返回,否则继续

2、检查foo是否是一个对象,bar为其的一个属性,如果是则返回,否则继续

3、如果foo是一个对象,检查bar是否为一个有效的方法,是则调用,否则继续

4、如果foo是一个对象,检查是否存在getBar方法存在,是则调用,否则继续

5、如果foo是一个对象,检查是否存在isBar方法存在,是则调用,否则继续

6、如果都不满足,最后返回NULL

foo['bar']只适用于数组,只进行两步检查:

1、检查foo是否是一个数组且bar是其的有效键名,如果是则返回,否则继续

2、返回NULL

 

所以主题开发者可以优先使用点号方式,注意foo.barbar可以是数字,代表数组的数字索引,如果此时使用中括号方式,数字加不加引号都没有关系

如果想访问一个变量的动态属性,可以使用attribute函数代替,见后

 

{{ "字面量" }}  {{ "{{}}" }}

可以通过这种方式直接输出字面量

 

全局变量:

是指在模板中总是有效的全局变量,默认有如下:

_self:引用到当前模板,值为不带路径的模板文件名

_context:引用到当前上下文,也就是$twig->render()的第二个参数,她总是数组

_charset:引用到当前模板的字符集,值如“UTF-8

开发者可以通过扩展提供更多全局变量,见开发者篇

 

设置变量:

模板开发者可以在模板中创建变量,使用“set”:

{% set foo = 'foo' %}

{% set foo = [1, 2] %}

{% set foo = {'foo': 'bar'} %}

 

操作符:

操作符优先级由低到高依次为(以“,”分隔):

b-and, b-xor, b-or, or, and, ==, !=, <, >, >=, <=, in, matches, starts with, ends with, .., +, -, ~, *, /, //, %, is, **, |, [], .

点号操作符优先级最高,所有操作符如下:

 

数学运算符:

在模板中可以使用算术运算符号:

+(加),-(减),*(乘),/(除),%(求余),

//(相除后向下取整,舍去法取整,如20//7结果为2-20//73),

**(幂运算,2**3等于823次方)

 

逻辑运算符:

and(与),or(或),not(非)

按位与、或、异或:b-and b-or b-xor

逻辑运算符是大小写敏感的,必须全小写

 

比较运算符:

可用常规运算符如:==, !=, <, >, >=, <=

注意没有“===”、“<>”,额外的运算符有:starts withends with

{% if 'Fabien' starts with 'F' %}

{% endif %}

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

{% endif %}

他们检查是否以字符串开始或结束,是大小写敏感的

更加复杂的比较运算符可用使用正则表达式:matches,示例如下:

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

{% endif %}

注意正则表达式中有“\”时,需要双转义

 

包含操作符:

使用“in”或“not in”以测试是否被包含:

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

{{ 'cd' in 'abcde' }}

{% if 1 not in [1, 2, 3] %} 等价于:{% if not (1 in [1, 2, 3]) %}

 

测试操作符:

twig中设置了一些测试表达式,可用“is”、“is not”操作符进行测试:

{{ num is odd }}

这测试一个数是否为奇数,更多测试表达式如下:

constantdefineddivisiblebyemptyeveniterablenulloddsameas

见:https://twig.symfony.com/doc/1.x/

 

其他操作符:

|”:管道符,用于应用一个过滤器

 

..”:双点号,用于创建一个数组

如在{% set a= 1..50 %}a将是元素从1开始50结束的数组,等效于{{ range(1, 50) }}

 

~”:连接符,完全等同于php的点号“.”,用于将操作数转化为字符并连接再一起

 

?:”:三元操作符,与php等效,从 Twig 1.12.0开始,以下用法是等效的:

{{ foo ?: 'no' }} {{ foo ? foo : 'no' }} 相同

{{ foo ? 'yes' }} {{ foo ? 'yes' : '' }} 相同

??”:假设{{ foo ?? 'no' }},如果foo被定义了且不为null那么就返回foo的值,否则返回“no

 

表达式插入字符串中:

可以通过“#{ }”向双引号内的字符串中插入表达式的值(单引号无效;必须是表达式,单独用于模板无效):

{{ "foo #{bar} baz" }}

{{ "foo #{1 + 2} baz" }}

 

空格控制:

默认情况下,标签后的第一个换行符被删除,但随后的换行、制表tab、空格等空白不会被修改,可以使用“spaceless”标签去移除一段内容的所有空白:

{% spaceless %}

    <div>

        <strong>foo bar</strong>

    </div>

{% endspaceless %}

这将输出:

<div><strong>foo bar</strong></div>

也可以在标签内使用减号来删除围绕标签的前或后空白:

{{- value -}}

此时减号被重载为空白修饰符,不必成对使用

 

 

过滤器:

过滤器用于对变量进行修改,使用管道符号“|”分隔,可以使用链式写法,前面的输出是后面的输入,如对变量name去除html标签,并采用标题格式(每个单词首字母大写):

{{ name|striptags|title }}

过滤器可以带参数,如将数组元素连接起来:

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

也可以对整段内容使用过滤器,如将一句话大写:

{% filter upper %}

    This text becomes uppercase

{% endfilter %}

twig默认提供的过滤器请见:\Twig_Extension_Core::getFilters

或官方文档:https://twig.symfony.com/doc/1.x/

开发者可以通过扩展提供更多过滤器

 

 

字符转义:

有些变量中的内容会影响html标签,比如尖括号、单双引号、和号&等等,那么就需要转义,有两种处理办法(可混用):

1、使用选项参数autoescape自动转义全部模板变量,见前文介绍,默认是开启的,转义策略是html

2、将autoescape设置为false关闭全局变量自动转义,此时模板开发者需要对不信任的变量手动转义,操作如下:

{{ yunke.risk|e }}

形式上这和使用过滤器是一样的,“e”是“escape”的缩写,默认是使用“html”转义,需要指定其他策略请:

{{ yunke.risk|e('js') }}

可用的策略参数有:jscsshtmlurlhtml_attr

除对单个变量转义和全局转义外,还可以对模板里一段内容中的全部变量转义(局部转义):

{% autoescape 'js' %}

    只要在这个标签内部的任何变量都会转义,注意是变量,也就是{{}}里的内容,模板内容不会转义

{% endautoescape %}

省略参数则默认使用html转义,开启局部或全局变量转义时,需要输出不转义内容要使用如下方式:

{{ var|raw }}

不管全局转义如何设置,autoescape标签将改变局部的转义模式,如下:

{% autoescape 'html' %}

    {{ var }}   {#不论全局转义如何设置 var只进行html转义 #}

    {{ var|raw }}      {# var 不转义#}

    {{ var|escape }}   {# var 只转义一次 不会双转义 #}

{% endautoescape %}

注意:标签autoescape不会影响到其内部使用included包含进来的模板

 

开启全局或局部转义后有如下规则需要注意:

不对字面量转义:

{{ "Twig<br />" }} {# 不转义 #}

{% set text = "Twig<br />" %}

{{ text }} {# 将转义#}

 

表达式结果:

{{ foo ? "Twig<br />" : "<br />Twig" }} {# 不转义 #}


{% set text = "Twig<br />" %}

{{ foo ? text : "<br />Twig" }} {#不论foo为真或假 都会转义结果#}


{% set text = "Twig<br />" %}

{{ foo ? text|raw : "<br />Twig" }} {#不论foo为真或假 都会转义结果 #}


{% set text = "Twig<br />" %}

{{ foo ? text|escape : "<br />Twig" }} {# 当转义策略和外部策略相同时不会再次转义#}

 

过滤器顺序:

转义被用在过滤器后,输出前,如:

{{ var|upper }} 等价于 {{ var|upper|escape }}

过滤器“raw”应该被用在最后:

{{ var|raw|upper }} {# 将转义 #}

{{ var|upper|raw }} {# 不转义#}

如果最后一个过滤器和当前转义策略相同,那么不会被再次运用:

{% autoescape 'js' %}

    {{ var|escape('html') }} {# 将再次对结果运用js转义 #}

    {{ var }} {# 只运用js转义 #}

    {{ var|escape('js') }} {# 不会再次转义 #}

{% endautoescape %}

 

变量转义有局限性,假设在全局转义为js时,以下代码的结果不是你想象的样子:

{{ yunke.risk|raw ~ yunke.risk }}

她看起来是原文本加js转义后的结果,但实际上全部是js转义的结果,和没有加“raw”过滤器时效果一样,所以我们在设计模板时应当尽量避免复杂的转义并充分测试,

 

函数:

可以像php一样使用函数,如:

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

    {{ i }},

{% endfor %}

Twig 1.12开始调用函数时,可不按照参数顺序赋值,可以指定函数原型中的参数名,如:

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

    {{ i }},

{% endfor %}

这样使得语义更加明确,可以忽略参数顺序,仅为部分参数赋值,其他参数使用默认值,也可以顺序方式和指定参数名方式混用,但顺序方式传递的参数必须在指定名字的参数前面,如:

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

函数的参数名可在官方手册对应函数介绍的参数一节看到:

https://twig.symfony.com/doc/1.x/

开发者可以通过扩展提供更多函数

 

控制结构:

用于条件判断、循环遍历等,控制结构位于{% ... %}中:

遍历结构:

<ul>

    {% for user in users %}

        <li>{{ user.username|e }}</li>

    {% endfor %}

</ul>

 

没有遍历内容时可以显示默认值:

{% for user in users %}

    *<li>{{ user.username|e }}</li>

{% else %}

    No users have been found.

{% endfor %}

 

遍历变量键名:

<h1>Members</h1>

<ul>

    {% for key in users|keys %}

        <li>{{ key }}</li>

    {% endfor %}

</ul>

 

遍历键和值:

<h1>Members</h1>

<ul>

    {% for key, user in users %}

        <li>{{ key }}: {{ user.username|e }}</li>

    {% endfor %}

</ul>

 

添加条件遍历,仅遍历条件为真的条目:

<ul>

    {% for user in users if user.active %}

        <li>{{ user.username|e }}</li>

    {% endfor %}

</ul>

 

遍历部分内容:

 <h1>Top Ten Members</h1>
<ul>
    {% for user in users|slice(0, 10) %}
        <li>{{ user.username|e }}</li>
    {% endfor %}
</ul>

 

for结构中可以使用特殊变量loop,如:

loop.index:当前迭代了第几次,从1开始

loop.index0:当前迭代了第几次,从0开始

loop.revindex:剩余迭代次数,最后是1

loop.revindex0:剩余迭代次数,最后是0

loop.first:是否为第一次迭代

loop.last:是否为最后一次迭代

loop.length:迭代的条目总数

loop.parent:引用到外层循环上下文

在指定循环条件时,loop变量是无效的

 

注意在for中没有break 或者 continue结构,遍历可以针对数组或者是实现了迭代器接口的对象

 

条件判断:

{% if users|length > 0 %}

show user

{% endif %}

 

也可以测试是否为空:

{% if users %}

    <ul>

        {% for user in users %}

            <li>{{ user.username|e }}</li>

        {% endfor %}

    </ul>

{% endif %}

 

取反:

{% if not user.subscribed %}

    <p>You are not subscribed to our mailing list.</p>

{% endif %}

也可以多分枝条件判断:

{% if 3 > yunke|length > 0 %}

    show 0-3

{% elseif 5 > yunke|length >= 3 %}

    show 3-5

{% else %}

    show 5-..

{% endif %}

 

是否为true规则和php一样:

空字符串:false

数字0: false

字符串:true

非零数字:     true

空白字符串:true

字符串“0”:false

空数组:false

NULL:false

非空数组:true

对象:true

 

作用域控制:

使用with标签可以创建一个新的作用域,里面的变量仅在内部有效,标签外部无效,示例如下:

{% with %}

    {% set foo = 42 %}

    {{ foo }}           foo is 42 here

{% endwith %}

变量foo在该标签以外是访问不到的,以上列子还可以换一种方式书写:

{% with { foo: 42 } %}

    {{ foo }}           foo is 42 here

{% endwith %}

也就是将变量集中到哈希中传入;默认情况下新建的作用域内可以访问外部变量,可以使用以下方式禁止:

{% set bar = 'bar' %}

{% with { foo: 42 } only %}

    {# only foo is defined #}

    {# bar is not defined #}

{% endwith %}

 

和普通编程语言相比没有while(){}do{}while()等结构,但twig的强大之处就是可以通过添加扩展的方式让她有,不过默认是没有的

 

加载其他模板:

在一个模板中可以通过如下方式加载其他模板:

{% include('sidebar.html') %}

也可以使用变量,如:

{% include var ~ '_foo.html' %}

实际上include关键词后可以是任意表达式,更复杂的如:

{% include var|default('index') ~ '_foo.html' %}

通过这种方式包含其他模板后,在include语句位置能使用的有效变量,在被加载的模板中也有效,如下:

{% for box in boxes %}

    {{ include('render_box.html') }}

{% endfor %}

render_box.html中可以使用变量box,被加载的模板名依赖于加载器的类型,如果是文件系统加载器,那么可以使用路径名。

 

模板继承:

一个模板可以把一个区域定义成块,这样其他模板可以声明继承该模板,声明后就成了该模板的子模板,相对的该模板就是父模板,子模板可以通过块名覆写父模板中定义的块,如果不覆写将使用父模板的内容,这称为模板继承,父模板声明块和子模板覆写块都使用如下方式:

{% block blockName %}…{% endblock %}

在子模板中声明继承需在第一行使用如下语句:

{% extends "base.html" %}

这里extends可以使用表达式以加载不同模板,如:

{% extends request.ajax ? "base_ajax.html" : "base.html" %}

模板继承示例如下,比如a.html.twig是父模板,内容如下:

<!DOCTYPE html>

<html lang="zh-cn">

<head>

    <meta charset="UTF-8">

    <title>twig</title>

</head>

<body>

{% block yunke %}

    <div>我是父模板a.html.twig中的内容</div>

{% endblock %}

</body>

</html>

 

b.html.twig是子模板,内容如下:

{% extends "a.html.twig" %}

{% block yunke %}

    <div>我是子模板b.html.twig中的内容</div>

{{ parent() }}

{% endblock %}

 

使用echo $twig->render('b.html.twig');将输出:

<!DOCTYPE html>

<html lang="zh-cn">

<head>

    <meta charset="UTF-8">

    <title>twig</title>

</head>

<body>

    <div>我是子模板b.html.twig中的内容</div>

    <div>我是父模板a.html.twig中的内容</div>


</body>

</html>

 

如你所见{{ parent() }}用于输出父模板中的块内容

不管是子模板还是父模板,他们共享相同的上下文变量

需要注意如果B继承了A,也就是说BA的子模板,那么在输出时B里面只能对A的块进行覆写,不能输出块外的内容,但b里面可进行变量赋值等非输出操作,在b里的逻辑先于a执行,因此在b中对变量或上下文的赋值将应用在a

 

宏命令Macros

当有些模板内容会被反复多次用到时,可以将其定义为宏,在使用的地方进行宏调用即可,里面需要用到的变量可以通过宏参数传入,这有点像编程语言中定义函数,新建一个模板,在里面定义宏(如同在函数库文件中定义函数),假设模板名为macrod.html.twig,内容如下:

{% macro input(name, value = "", type = "text", size = 20) %}

    <input type="{{ type }}" name="{{ name }}" value="{{ value|e }}" size="{{ size }}" />

{% endmacro %}


{% macro user(name="匿名用户", tel = "未知") %}

用户名:{{ name }}  电话号码:{{ tel }}

{% endmacro %}

 

这就在一个文件中声明了两个宏,在其他模板中需要用到时,可以这样:

{% import "macrod.html.twig" as lib %}

<p>{{ lib.input('username') }}</p>

<p>{{ lib.user('yunke',"13812345678") }}</p>

<p>{{ lib.user() }}</p>

这将输出:

<p>    <input type="text" name="username" value="" size="20" />

</p>

<p>用户名:yunke  电话号码:13812345678

</p>

<p>用户名:匿名用户  电话号码:未知

</p>

 

导入语句{% import "macrod.html.twig" as lib %}只需要放在宏调用前即可,上列是将整个文件引用进来然后给了一个别名“lib”,你也可以只导入某具体的宏,输出效果是一样的,如下:

{% from 'macrod.html.twig' import user as id %}

<p>{{ id('yunke',"13812345678") }}</p>

在上面的列子中,如果在macrod.html.twig中出现任何宏声明之外的内容,将会被忽略,不会引起错误,我们应该认识到宏模板文件应该只用来定义宏

如果在进行宏调用时传递了多于的参数,那么多于的参数将以列表方式储存在特殊变量varargs中,在宏内可以使用for结构去遍历她,如下:

{% macro user(name="匿名用户", tel = "未知") %}

用户名:{{ name }}  电话号码:{{ tel }}  {% for arg in varargs  %}额外参数:{{ arg }}{% endfor %}

{% endmacro %}

此时如果没有传递多于参数,将不会有额外部分的显示,换句话说varargs不包含有声明的参数

在宏声明时最佳实践是在参数上定义默认值,否则在宏内使用该参数时应当给出默认值

 

 

模板编码标准:

在编写模板代码时推荐遵从官方的标准编码风格,这不是强制的,但这样有较好的可读性,也叫做官方推荐最佳实践,简要如下:

1、在开始定界符后和结束定界符前,有且仅有一个空格

2、当使用空白控制符“-”时,不要在她和定界符之间放置任何空白

3、在操作符前后各使用一个空格,有且仅有一个

4、在数组的“,”和哈希表的“:”之后有且仅有一个空格

5、在开始圆括号后、结束圆括号前不要放置任何空白

6、在引号前后不要放置空白

7、在操作符| . .. []前后不要放置空白

8、过滤器和函数的圆括号前后不要空白

9、使用小写变量名,单词间用下划线

10、对齐标签,统一缩进

 

官网最佳实践网址为:

https://twig.symfony.com/doc/1.x/coding_standards.html

 

 

补充:

1、模板开发者可以在这里在线测试自己的模板:

https://twigfiddle.com

可以通过多种格式(yamljsonxmlini)传递变量,然后显示

2twig模板引擎是高度可扩展的,开发者可以通过扩展提供更多全局变量、过滤器、函数、操作符、控制结构等等,请见开发者篇

本书共97小节:

评论 (写第一个评论)