嫩枝

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

Syob娱乐下载mfony产品
文档 延长枝
您正在阅读Twig 2.x的文档。欧宝官网下载app切换到Twig的文档欧宝官网下载app1.倍3.倍

延长枝

树枝可以以多种方式延伸;您可以添加额外的标记、筛选器、测试、操作符、全局变量和函数。您甚至可以使用节点访问者扩展解析器本身。

请注意

本章的第一部分描述了如何扩展Twig。如果您希望在不同的项目中重用更改,或者希望与他人共享更改,那么您应该按照以下部分所述创建一个扩展。

谨慎

当扩展Twig而不创建扩展时,Twig将不能在PHP代码更新时重新编译模板。要实时查看更改,要么禁用模板缓存,要么将代码打包到扩展中(参见本章的下一节)。

在扩展Twig之前,您必须了解所有不同可能的扩展点之间的差异,以及何时使用它们。

首先,请记住Twig有两个主要的语言结构:

  • {{}}:用于打印表达式求值的结果;
  • {% %}:用于执行语句。

为了理解为什么Twig公开了这么多扩展点,让我们看看如何实现一个扩展点Lorem ipsum生成器(它需要知道要生成的单词数)。

你可以使用lipsum标签

1
{%lipsum40%}

这是可行的,但是使用标签lipsum不是个好主意,至少有三个主要原因:

  • lipsum不是一种语言结构;
  • 标签输出一些东西;
  • 标签不灵活,因为你不能在表达式中使用它:

    1
    {{'some text' ~ {% lipsum 40 %} ~ 'some more text'}}

事实上,您很少需要创建标记;这是个好消息,因为标记是最复杂的欧宝平台是合法的吗扩展点。

现在,我们用alipsum过滤器

1
{{40|lipsum}}

同样,这是有效的。但是过滤器应该将传递的值转换为其他值。在这里,我们使用值表示要生成的字数(因此,40是过滤器的参数,而不是我们要转换的值)。

接下来,让我们使用alipsum函数

1
{{lipsum(40)}}

开始吧。对于这个特定的示例,函数的创建就是要使用的扩展点。你可以在任何一个表达被接受的地方使用它:

1 2 3
{{'some text' ~ lipsum(40) ~ 'some more text'}}{%唇膏=唇膏(40)%}

最后,您还可以使用a全球对象,使用一个方法生成lorem ipsum文本:

1
{{text.lipsum(40)}}

根据经验,对于常用的特性使用函数,对于其他所有特性使用全局对象。

当你想要扩展Twig时,请记住以下几点:

什么? 实现困难吗? 多长时间? 什么时候?
简单的 频繁的 内容生成
全球 简单的 频繁的 Helper对象
函数 简单的 频繁的 内容生成
过滤器 简单的 频繁的 值转换
标签 复杂的 罕见的 DSL语言构造
测验 简单的 罕见的 布尔决定
操作符 简单的 罕见的 值转换

全局变量

一个全局变量就像任何其他模板变量一样,除了它在所有模板和宏中可用:

1 2
嫩枝\树枝\环境(加载程序);嫩枝->addGlobal (“文本”Text ());

然后可以使用文本变量在模板中的任意位置:

1
{{text.lipsum(40)}}

过滤器

创建过滤器包括将名称与PHP可调用对象关联:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16
//匿名函数过滤器\树枝\ TwigFilter (“rot13”函数字符串返回函数字符串);});//或一个简单的PHP函数过滤器\树枝\ TwigFilter (“rot13”“函数”);//或类静态方法过滤器\树枝\ TwigFilter (“rot13”, (“SomeClass”“rot13Filter”]);过滤器\树枝\ TwigFilter (“rot13”“SomeClass:: rot13Filter”);//或类方法过滤器\树枝\ TwigFilter (“rot13”, (“rot13Filter”]);//下面的一个需要一个运行时实现(参见下面的更多信息)过滤器\树枝\ TwigFilter (“rot13”, (“SomeClass”“rot13Filter”]);

的第一个参数传递给\树枝\ TwigFilter构造函数是您将在模板中使用的过滤器的名称,第二个是与它关联的PHP可调用对象。

然后,将过滤器添加到Twig环境中:

1 2
嫩枝\树枝\环境(加载程序);嫩枝->addFilter (过滤器);

下面是如何在模板中使用它:

1 2 3
{{'Twig'|rot13}}{#输出Gjvt #}

当被Twig调用时,PHP可调用对象接收过滤器的左侧(在管道之前)|)作为第一个参数,并将额外的参数传递给过滤器(在括号内())作为额外参数。

例如,以下代码:

1 2
{{|“树枝”较低的}}{{现在|日期(d / m / Y)}}

编译成如下内容:

1 2
<?php回声函数“树枝”? ><?php回声twig_date_format_filter (现在' d / m / Y '? >

\树枝\ TwigFilter类的最后一个参数为一个选项数组:

1
过滤器\树枝\ TwigFilter (“rot13”“函数”选项);

Environment-aware过滤器

如果要访问筛选器中的当前环境实例,请设置needs_environment选项真正的;Twig将当前环境作为过滤器调用的第一个参数传递:

1 2 3 4 5 6
过滤器\树枝\ TwigFilter (“rot13”函数(\树枝\环境env字符串//获取当前字符集字符集env->getCharset ();返回函数字符串);},“needs_environment”= >真正的]);

环境敏感的过滤器

如果要访问筛选器中的当前上下文,请设置needs_context选项真正的;Twig将当前上下文作为第一个参数传递给过滤器调用(如果needs_environment也设置为真正的):

1 2 3 4 5 6 7
过滤器\树枝\ TwigFilter (“rot13”函数上下文字符串/ /……},“needs_context”= >真正的]);过滤器\树枝\ TwigFilter (“rot13”函数(\树枝\环境env上下文字符串/ /……},“needs_context”= >真正的“needs_environment”= >真正的]);

自动转义

如果启用了自动转义,则可以在打印之前转义过滤器的输出。如果您的过滤器充当逃逸器(或显式输出HTML或JavaScript代码),您将希望打印原始输出。在这种情况下,设置is_safe选择:

1
过滤器\树枝\ TwigFilter (“nl2br”“nl2br”, (“is_safe”= > [“html”]]);

有些过滤器可能需要处理已经转义或安全的输入,例如向原本不安全的输出添加(安全的)HTML标记。在这种情况下,设置pre_escape选项,在输入数据通过过滤器运行之前转义输入数据:

1
过滤器\树枝\ TwigFilter (“somefilter”“somefilter”, (“pre_escape”= >“html”“is_safe”= > [“html”]]);

可变的过滤器

当筛选器应接受任意数量的参数时,设置is_variadic选项真正的;Twig将额外的参数作为最后一个参数作为数组传递给过滤器调用:

1 2 3
过滤器\树枝\ TwigFilter (“缩略图”函数文件数组,选项= [])/ /……},“is_variadic”= >真正的]);

请注意命名参数传递给可变参数过滤器不能检查有效性,因为它们将自动结束在选项数组中。

动态过滤器

包含特殊属性的筛选器名称字符是一个动态过滤器Part将匹配任何字符串:

1 2 3
过滤器\树枝\ TwigFilter (‘* _path‘函数的名字参数/ /……});

下面的过滤器与上面定义的动态过滤器匹配:

  • product_path
  • category_path

一个动态过滤器可以定义多个动态部分:

1 2 3
过滤器\树枝\ TwigFilter (“* _path_ *”函数的名字后缀参数/ /……});

过滤器在常规过滤器参数之前,但在环境和上下文之后接收所有动态部分值。例如,调用“foo”| a_path_b ()将导致将以下参数传递给过滤器:('a', 'b', 'foo')

弃用过滤器

属性可以将筛选器标记为已弃用弃用选项真正的.当有意义时,你也可以给出一个替代过滤器来替换已弃用的过滤器:

1 2 3
过滤器\树枝\ TwigFilter (“过时的”函数()/ /……},“弃用”= >真正的“替代”= >“new_one”]);

当过滤器被弃用时,Twig在编译使用它的模板时发出弃用通知。看到食谱获取更多信息。

功能

函数的定义方式与筛选器完全相同,但是需要创建\树枝\ TwigFunction

1 2 3 4 5
嫩枝\树枝\环境(加载程序);函数\树枝\ TwigFunction (“function_name”函数()/ /……});嫩枝->addFunction (函数);

函数支持与筛选器相同的特性,除了pre_escape而且preserves_safety选项。

测试

的定义方式与筛选器和函数完全相同,但需要创建的实例\树枝\ TwigTest

1 2 3 4 5
嫩枝\树枝\环境(加载程序);测验\树枝\ TwigTest (“test_name”函数()/ /……});嫩枝->addTest (测验);

测试允许您创建用于计算布尔条件的自定义应用程序特定逻辑。作为一个简单的例子,让我们创建一个Twig测试,检查对象是否为“红色”:

1 2 3 4 5 6 7 8 9 10 11
嫩枝\树枝\环境(加载程序);测验\树枝\ TwigTest (“红色”函数价值如果收取价值->颜色)& &价值->颜色= =“红色”) {返回真正的;}如果收取价值->油漆)& &价值->油漆= =“红色”) {返回真正的;}返回;});嫩枝->addTest (测验);

测试函数必须总是返回真正的/

创建测试时,可以使用node_class选项提供自定义测试编译。如果您的测试可以被编译成PHP原语,这是很有用的。这被许多内置到Twig的测试所使用:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
名称空间应用程序使用嫩枝环境使用嫩枝节点表达式TestExpression使用嫩枝TwigTest嫩枝环境(加载程序);测验TwigTest (“奇怪”, (“node_class”= > OddTestExpression::类);嫩枝->addTest (测验);OddTestExpression扩展TestExpression公共函数编译(\树枝\编译器编译器编译器->生(“(”->subcompile (->getNode (“节点”))->生(' % 2 != 0'->生(“)”);}}

上面的示例展示了如何创建使用节点类的测试。节点类可以访问一个子节点节点.这个子节点包含正在测试的值。当奇怪的过滤器用于如下代码:

1
{%如果My_value为奇数%}

节点子节点将包含的表达式my_value.基于节点的测试还可以访问参数节点。这个节点将包含提供给您的测试的各种其他参数。

2.6

动态测试支持在Twig 2.6中添加。

如果希望向测试传递可变数量的位置或命名参数,请设置is_variadic选项真正的.测试支持动态名称(请参阅动态筛选器了解语法)。

标签

像Twig这样的模板引擎最令人兴奋的特性之一是可以定义new语言结构.这也是最复杂的功能,因为您需要了解Twig的内部工作原理。

但是大多数时候,标签是不需要的:

  • 如果标记生成一些输出,则使用函数代替。
  • 如果标记修改了一些内容并返回它,则使用过滤器代替。

    例如,如果您想创建一个将Markdown格式的文本转换为HTML的标记,请创建一个减价而不是过滤:

    1
    {{'**markdown** text'|减价}}

    如果要对大量文本使用此筛选器,请使用应用标签:

    1 2 3 4 5 6
    {%应用减价%}Title =====比创建一个标签好得多,因为你可以**组成**过滤器。{%endapply%}

请注意

应用标签是在Twig 2.9引入的;使用过滤器使用以前的版本标记。

  • 如果标记没有输出任何内容,只是因为副作用而存在,则创建一个函数返回任何内容,并通过过滤器标签。

    例如,如果要创建记录文本的标记,请创建日志函数,并通过标签:

    1
    {%log(' log一些东西')%}

如果您仍然想为一个新的语言结构创建一个标记,那太好了!

我们来创建一个标记,该标记允许从模板中定义简单变量。标签可以像下面这样使用:

1 2 3 4 5
{%Name = "value" %}{{name}}{#应该输出值#}

请注意

标签是核心扩展的一部分,因此总是可用的。内置版本稍微强大一些,默认情况下支持多重赋值。

定义一个新标签需要三个步骤:

  • 定义一个Token Parser类(负责解析模板代码);
  • 定义一个Node类(负责将解析的代码转换为PHP);
  • 注册标记。

注册一个新标记

方法添加标记addTokenParser方法。\树枝\环境实例:

1 2
嫩枝\树枝\环境(加载程序);嫩枝->addTokenParser (Project_Set_TokenParser ());

定义令牌解析器

现在,让我们看看这个类的实际代码:

12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20
Project_Set_TokenParser扩展嫩枝TokenParserAbstractTokenParser公共函数解析(\树枝\令牌令牌解析器->解析器;解析器->getStream ();的名字->期望(\树枝\令牌::NAME_TYPE)->getValue ();->期望(\树枝\令牌::OPERATOR_TYPE,“=”);价值解析器->getExpressionParser ()->parseExpression ();->期望(\树枝\令牌::BLOCK_END_TYPE);返回Project_Set_Node (的名字价值令牌->getLine (),->getTag ());}公共函数getTag()返回“设置”;}}

getTag ()方法必须返回要解析的标记

parse ()方法时调用标签。它应该返回一个\ \树枝\节点实例,该实例表示节点Project_Set_Node调用创建将在下一节中解释)。

解析过程简化了,这要归功于您可以从令牌流调用的一堆方法($ this - >解析器- > getStream ()):

  • getCurrent ():获取流中的当前令牌。
  • next ():移动到流中的下一个标记,而是返回原来的
  • 测试类型($)测试(美元值)测试(类型,价值美元):确定当前令牌是否为特定类型或值(或两者都是)。该值可以是几个可能值的数组。
  • Expect ($type[, $value[, $message]]):如果当前令牌不是给定类型/值,则抛出语法错误。否则,如果类型和值正确,则返回令牌,流移动到下一个令牌。
  • 看():查看下一个令牌,但不消耗它。

解析表达式是通过调用parseExpression ()就像我们对标签。

提示

阅读现有的TokenParser类是学习解析过程的所有基本细节的最佳方法。

定义节点

Project_Set_Node课程本身很短:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Project_Set_Node扩展嫩枝节点节点公共函数__construct的名字, \树枝\节点\ \ AbstractExpression表达式价值标签= null)::__construct ([“价值”= >价值]、[“名字”= >的名字],标签);}公共函数编译(\树枝\编译器编译器编译器->addDebugInfo (->写($上下文[\”->getAttribute (“名字”).'\'] = '->subcompile (->getNode (“价值”))->生(”;\ n”);}}

编译器实现了一个流动的接口,并提供了一些方法来帮助开发人员生成漂亮和可读的PHP代码:

  • subcompile ():编译节点。
  • 生():按原样写入给定的字符串。
  • write ():通过在每行开头添加缩进来写入给定的字符串。
  • 字符串():写入带引号的字符串。
  • repr ():编写给定值的PHP表示(参见\树枝\ \ ForNode节点使用示例)。
  • addDebugInfo ():将原模板文件中与当前节点相关的行添加为注释。
  • 缩进():缩进生成的代码(请参阅\树枝\ \ BlockNode节点使用示例)。
  • 减少缩进():超出生成的代码(请参阅\树枝\ \ BlockNode节点使用示例)。

创建扩展

编写扩展的主要动机是将经常使用的代码转移到可重用类中,例如添加对国际化的支持。扩展可以定义标记、筛选器、测试、操作符、函数和节点访问者。

大多数时候,为你的项目创建一个单独的扩展是很有用的,以承载你想要添加到Twig的所有特定的标签和过滤器。

提示

当你把你的代码打包到一个扩展中时,Twig是足够聪明的,无论何时你对它做了更改(当auto_reload启用)。

扩展是实现以下接口的类:

12 34 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
接口嫩枝扩展ExtensionInterface/** *返回要添加到现有列表的令牌解析器实例。* *@return\树枝\ TokenParser \ TokenParserInterface [] * /公共函数getTokenParsers()/** *返回要添加到现有列表的节点访问者实例。* *@return\树枝\ NodeVisitor \ NodeVisitorInterface [] * /公共函数getNodeVisitors()/** *返回要添加到现有列表的过滤器列表。* *@return\树枝\ TwigFilter [] * /公共函数getFilters()/** *返回要添加到现有列表的测试列表。* *@return\树枝\ TwigTest [] * /公共函数getTests()/** *返回要添加到现有列表的函数列表。* *@return\树枝\ TwigFunction [] * /公共函数getFunctions()/** *返回要添加到现有列表的操作符列表。* *@returnarray第一个一元操作符数组,第二个二元操作符数组*/公共函数getOperators();}

为了保持扩展类的简洁,请从内置的\树枝\ \ AbstractExtension延伸类,而不是实现接口,因为它为所有方法提供了空实现:

1 2 3
Project_Twig_Extension扩展嫩枝扩展AbstractExtension{}

这个扩展现在什么都不做。我们将在下一节中定制它。

您可以将扩展保存在文件系统的任何位置,因为必须显式地注册所有扩展才能在模板中使用。

方法可以注册扩展addExtension ()方法。环境对象:

1 2
嫩枝\树枝\环境(加载程序);嫩枝->addExtension (Project_Twig_Extension ());

提示

Twig核心扩展是扩展如何工作的很好的例子。

全局变量

方法在扩展中注册全局变量getGlobals ()方法:

1 2 3 4 5 6 7 8 9 10 11
Project_Twig_Extension扩展嫩枝扩展AbstractExtension实现了嫩枝扩展GlobalsInterface公共函数getGlobals()返回“文本”= >文本()];}/ /……

功能

方法将函数注册到扩展中getFunctions ()方法:

1 2 3 4 5 6 7 8 9 10 11
Project_Twig_Extension扩展嫩枝扩展AbstractExtension公共函数getFunctions()返回\树枝\ TwigFunction (“lipsum”“generate_lipsum”),);}/ /……

过滤器

要向扩展添加筛选器,需要重写getFilters ()方法。该方法必须返回一个添加到Twig环境的过滤器数组:

1 2 3 4 5 6 7 8 9 10 11
Project_Twig_Extension扩展嫩枝扩展AbstractExtension公共函数getFilters()返回\树枝\ TwigFilter (“rot13”“函数”),);}/ /……

标签

属性可以在扩展中添加标记getTokenParsers ()方法。这个方法必须返回一个添加到Twig环境的标签数组:

1 2 3 4 5 6 7 8 9
Project_Twig_Extension扩展嫩枝扩展AbstractExtension公共函数getTokenParsers()返回Project_Set_TokenParser ()];}/ /……

在上面的代码中,我们添加了一个新标记,该标记由Project_Set_TokenParser类。的Project_Set_TokenParser类负责解析标记并将其编译为PHP。

运营商

getOperators ()方法允许您添加新的操作符。下面是如何添加||,& &运营商:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Project_Twig_Extension扩展嫩枝扩展AbstractExtension公共函数getOperators()返回[[“!”= > [“优先”= >50“类”= > \树枝\节点\ \一元\ NotUnary表达式::类],],[“| |”= > [“优先”= >10“类”= > \树枝\节点\ \二进制\ OrBinary表达式::类,结合性的= > \树枝\ ExpressionParser::OPERATOR_LEFT),“& &”= > [“优先”= >15“类”= > \树枝\节点\ \二进制\ AndBinary表达式::类,结合性的= > \树枝\ ExpressionParser::Operator_left],],];}/ /……

测试

getTests ()方法允许您添加新的测试函数:

1 2 3 4 5 6 7 8 9 10 11
Project_Twig_Extension扩展嫩枝扩展AbstractExtension公共函数getTests()返回\树枝\ TwigTest (“甚至”“twig_test_even”),);}/ /……

定义vs运行时

Twig过滤器、函数和测试运行时实现可以定义为任何有效的PHP可调用对象:

  • 函数/静态方法:简单的实现和快速(使用的所有Twig核心扩展);但是运行时很难依赖于外部对象;
  • 闭包:执行简单;
  • 对象方法:如果您的运行时代码依赖于外部对象,则更加灵活并且是必需的。

使用方法最简单的方法是在扩展本身上定义它们:

12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20 21
Project_Twig_Extension扩展嫩枝扩展AbstractExtension私人rot13Provider公共函数__constructrot13Provider->rot13Provider =rot13Provider;}公共函数getFunctions()返回\树枝\ TwigFunction (“rot13”, (“rot13”)));}公共函数rot13价值返回->rot13Provider->rot13 (价值);}}

这非常方便,但不建议这样做,因为它使模板编译依赖于运行时依赖项,即使它们并不需要(例如,将实例视为连接到数据库引擎的依赖项)。

可以将扩展定义与其运行时实现解耦\树枝\ RuntimeLoader \ RuntimeLoaderInterface环境中的实例,该实例知道如何实例化这样的运行时类(运行时类必须是可自动加载的):

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16
RuntimeLoader实现了嫩枝RuntimeLoaderRuntimeLoaderInterface公共函数负载//实现创建$class实例的逻辑//并注入它的依赖项//大多数时候,这意味着使用你的依赖注入容器如果“Project_Twig_RuntimeExtension”= = =) {返回Rot13Provider ());}其他的/ /……}}}嫩枝->addRuntimeLoader (RuntimeLoader ());

请注意

Twig附带一个PSR-11兼容的运行时加载器(\树枝\ RuntimeLoader \ ContainerRuntimeLoader).

现在可以将运行时逻辑移动到新的Project_Twig_RuntimeExtension类,并直接在扩展中使用它:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
Project_Twig_RuntimeExtension私人rot13Provider公共函数__constructrot13Provider->rot13Provider =rot13Provider;}公共函数rot13价值返回->rot13Provider->rot13 (价值);}}Project_Twig_Extension扩展嫩枝扩展AbstractExtension公共函数getFunctions()返回\树枝\ TwigFunction (“rot13”, (“Project_Twig_RuntimeExtension”“rot13”]),/ /或\树枝\ TwigFunction (“rot13”“Project_Twig_RuntimeExtension:: rot13”),);}}

测试扩展

功能测试

通过在测试目录中创建以下文件结构,可以为扩展创建功能测试:

1 2 3 4 5 6 7 8 9 10 11
Fixtures/ filters/ foo。测试棒。测验函数s/ foo.test bar.test tags/ foo.test bar.test IntegrationTest.php

IntegrationTest.php文件应该是这样的:

12 3 4 5 6 7 8 9 10 11 12 13 14 15
Project_Tests_IntegrationTest扩展嫩枝测试IntegrationTestCase公共函数getExtensions()返回Project_Twig_Extension1 (),Project_Twig_Extension2 ()];}公共函数getFixturesDir()返回__DIR__“/夹具/”;}}

fixture示例可以在Twig存储库中找到测试/理解/夹具目录中。

节点测试

测试节点访问者可能很复杂,因此从\树枝\ \ NodeTestCase测试.示例可以在Twig存储库中找到测试/树枝节点目录中。

网站由ob娱乐下载和树枝,部署在
的树枝标志©2010-2023ob娱乐下载