Twig内部构件

Twig是非常可扩展的,你可以破解它。请记住,您可能应该在破解核心之前尝试创建一个扩展,因为大多数特性和增强都可以通过扩展来处理。想了解这一章对谁也有用。

树枝是怎么工作的?

Twig模板的渲染可概括为四个关键步骤:

  • Load 模板:如果模板已经编译,加载它并转到 评价 步骤,否则:
    • 首先, 莱克塞 将模板源代码标记成小块,以便于处理;
    • 然后, 语法分析器 将令牌流转换为有意义的节点树(抽象语法树);
    • 最后, 编译器 将AST转换为PHP代码。
  • 评估 模板:它意味着调用 display() 方法,并将其传递给上下文。

雷克瑟

lexer将模板源代码标记为令牌流(每个令牌都是 \Twig\Token ,流是 \Twig\TokenStream ). 默认的lexer可以识别13种不同的令牌类型:

  • \Twig\Token::BLOCK_START_TYPE\Twig\Token::BLOCK_END_TYPE :块的分隔符 ({{% %}}
  • \Twig\Token::VAR_START_TYPE\Twig\Token::VAR_END_TYPE :变量的分隔符 ({{{{ }}}}
  • \Twig\Token::TEXT_TYPE :表达式外的文本;
  • \Twig\Token::NAME_TYPE :表达式中的名称;
  • \Twig\Token::NUMBER_TYPE :表达式中的数字;
  • \Twig\Token::STRING_TYPE :表达式中的字符串;
  • \Twig\Token::OPERATOR_TYPE :操作员;
  • \Twig\Token::PUNCTUATION_TYPE :标点符号;
  • \Twig\Token::INTERPOLATION_START_TYPE\Twig\Token::INTERPOLATION_END_TYPE :字符串插值的分隔符;
  • \Twig\Token::EOF_TYPE :模板结束。

您可以通过调用 tokenize() 环境方法:

$stream = $twig->tokenize(new \Twig\Source($source, $identifier));

因为溪流有一个 __toString() 方法,您可以通过回显对象来获得它的文本表示形式:

echo $stream."\n";

下面是 Hello {{{{ name }}}} 模板:

1
2
3
4
5
TEXT_TYPE(Hello )
VAR_START_TYPE()
NAME_TYPE(name)
VAR_END_TYPE()
EOF_TYPE()

注解

默认的lexer (\Twig\Lexer )可以通过调用 setLexer() 方法:

$twig->setLexer($lexer);

语法分析器

解析器将令牌流转换为AST(抽象语法树)或节点树(的实例 \Twig\Node\ModuleNode ). 核心扩展定义了如下基本节点: forif , ... 以及表达式节点。

您可以通过调用 parse() 环境方法:

$nodes = $twig->parse($stream);

回显node对象可以很好地表示树:

echo $nodes."\n";

下面是 Hello {{{{ name }}}} 模板:

1
2
3
4
5
6
\Twig\Node\ModuleNode(
  \Twig\Node\TextNode(Hello )
  \Twig\Node\PrintNode(
    \Twig\Node\Expression\NameExpression(name)
  )
)

注解

默认解析器 (\Twig\TokenParser\AbstractTokenParser )可以通过调用 setParser() 方法:

$twig->setParser($parser);

编译器

最后一步由编译器完成。它以一个节点树作为输入,并生成可在运行时执行模板的PHP代码。

您可以使用 compile() 环境方法:

$php = $twig->compile($nodes);

生成的模板 Hello {{{{ name }}}} 模板如下所示(实际输出可能因使用的Twig版本而异):

/* Hello {{ name }} */
class __TwigTemplate_1121b6f109fe93ebe8c6e22e3712bceb extends Template
{
    protected function doDisplay(array $context, array $blocks = [])
    {
        // line 1
        echo "Hello ";
        echo twig_escape_filter($this->env, (isset($context["name"]) ? $context["name"] : null), "html", null, true);
    }

    // some more code
}

注解

默认编译器 (\Twig\Compiler )可以通过调用 setCompiler() 方法:

$twig->setCompiler($compiler);