Twig Internals

Twig is very extensible and you can hack it. Keep in mind that you should probably try to create an extension before hacking the core, as most features and enhancements can be handled with extensions. This chapter is also useful for people who want to understand how Twig works under the hood.

Twig は非常に拡張性が高く、ハックすることができます。ほとんどの機能と拡張機能は拡張機能で処理できるため、コアをハックする前に拡張機能を作成するようにしてください。この章は、Twig が内部でどのように機能するかを理解したい人にも役立ちます。

How does Twig work?

The rendering of a Twig template can be summarized into four key steps:

Twig テンプレートのレンダリングは、次の 4 つの主要なステップに要約できます。
  • Load the template: If the template is already compiled, load it and go to the evaluation step, otherwise:

    テンプレートをロードします: テンプレートが既にコンパイルされている場合は、それをロードして評価ステップに進みます。それ以外の場合:
    • First, the lexer tokenizes the template source code into small pieces for easier processing;
      まず、レクサーはテンプレートのソース コードをトークン化し、処理を容易にするために小さな断片にします。
    • Then, the parser converts the token stream into a meaningful tree of nodes (the Abstract Syntax Tree);
      次に、パーサーはトークン ストリームを意味のあるノードのツリー (抽象構文ツリー) に変換します。
    • Finally, the compiler transforms the AST into PHP code.
      最後に、コンパイラは AST を PHP コードに変換します。
  • Evaluate the template: It means calling the display() method of the compiled template and passing it the context.
    テンプレートを評価する: コンパイルされたテンプレートの display() メソッドを呼び出し、それにコンテキストを渡すことを意味します。

The Lexer

The lexer tokenizes a template source code into a token stream (each token is an instance of \Twig\Token, and the stream is an instance of \Twig\TokenStream). The default lexer recognizes 13 different token types:

lexer は、テンプレート ソース コードをトークン ストリームにトークン化します (各トークンは \Twig\Token のインスタンスであり、ストリームは \Twig\TokenStream のインスタンスです)。デフォルトのレクサーは、13 の異なるトークン タイプを認識します。
  • \Twig\Token::BLOCK_START_TYPE, \Twig\Token::BLOCK_END_TYPE: Delimiters for blocks ({% %})
    \Twig\Token::BLOCK_START_TYPE、\Twig\Token::BLOCK_END_TYPE: ブロックの区切り文字 ({% %})
  • \Twig\Token::VAR_START_TYPE, \Twig\Token::VAR_END_TYPE: Delimiters for variables ({{ }})
    \Twig\Token::VAR_START_TYPE、\Twig\Token::VAR_END_TYPE: 変数の区切り文字 ({{ }})
  • \Twig\Token::TEXT_TYPE: A text outside an expression;
    \Twig\Token::TEXT_TYPE: 式の外側のテキスト。
  • \Twig\Token::NAME_TYPE: A name in an expression;
    \Twig\Token::NAME_TYPE: 式の中の名前。
  • \Twig\Token::NUMBER_TYPE: A number in an expression;
    \Twig\Token::NUMBER_TYPE: 式の中の数値。
  • \Twig\Token::STRING_TYPE: A string in an expression;
    \Twig\Token::STRING_TYPE: 式の文字列。
  • \Twig\Token::OPERATOR_TYPE: An operator;
    \Twig\Token::OPERATOR_TYPE: 演算子。
  • \Twig\Token::PUNCTUATION_TYPE: A punctuation sign;
    \Twig\Token::PUNCTUATION_TYPE: 句読点;
  • \Twig\Token::INTERPOLATION_START_TYPE, \Twig\Token::INTERPOLATION_END_TYPE: Delimiters for string interpolation;
    \Twig\Token::INTERPOLATION_START_TYPE、\Twig\Token::INTERPOLATION_END_TYPE: 文字列補間の区切り文字。
  • \Twig\Token::EOF_TYPE: Ends of template.
    \Twig\Token::EOF_TYPE: テンプレートの終わり。

You can manually convert a source code into a token stream by calling the tokenize() method of an environment:

環境の tokenize() メソッドを呼び出すことで、ソース コードを手動でトークン ストリームに変換できます。
1
$stream = $twig->tokenize(new \Twig\Source($source, $identifier));

As the stream has a __toString() method, you can have a textual representation of it by echoing the object:

ストリームには __toString() メソッドがあるため、オブジェクトをエコーすることでテキスト表現を取得できます。
1
echo $stream."\n";

Here is the output for the Hello {{ name }} template:

Hello {{ name }} テンプレートの出力は次のとおりです。
1
2
3
4
5
TEXT_TYPE(Hello )
VAR_START_TYPE()
NAME_TYPE(name)
VAR_END_TYPE()
EOF_TYPE()

Note

ノート

The default lexer (\Twig\Lexer) can be changed by calling the setLexer() method:

デフォルトのレクサー (\Twig\Lexer) は、setLexer() メソッドを呼び出すことで変更できます。
1
$twig->setLexer($lexer);

The Parser

The parser converts the token stream into an AST (Abstract Syntax Tree), or a node tree (an instance of \Twig\Node\ModuleNode). The core extension defines the basic nodes like: for, if, ... and the expression nodes.

パーサーは、トークン ストリームを AST (抽象構文ツリー) またはアノード ツリー (\Twig\Node\ModuleNode のインスタンス) に変換します。コア拡張機能は、for、if、... および式ノードなどの基本ノードを定義します。

You can manually convert a token stream into a node tree by calling the parse() method of an environment:

環境の parse() メソッドを呼び出すことで、トークン ストリームをノード ツリーに手動で変換できます。
1
$nodes = $twig->parse($stream);

Echoing the node object gives you a nice representation of the tree:

ノード オブジェクトをエコーすると、ツリーの適切な表現が得られます。
1
echo $nodes."\n";

Here is the output for the Hello {{ name }} template:

Hello {{ name }} テンプレートの出力は次のとおりです。
1
2
3
4
5
6
\Twig\Node\ModuleNode(
  \Twig\Node\TextNode(Hello )
  \Twig\Node\PrintNode(
    \Twig\Node\Expression\NameExpression(name)
  )
)

Note

ノート

The default parser (\Twig\TokenParser\AbstractTokenParser) can be changed by calling the setParser() method:

setParser() メソッドを呼び出すことで、デフォルトのパーサー (\Twig\TokenParser\AbstractTokenParser) を変更できます。
1
$twig->setParser($parser);

The Compiler

The last step is done by the compiler. It takes a node tree as an input and generates PHP code usable for runtime execution of the template.

最後のステップはコンパイラによって行われます。ノード ツリーを入力として受け取り、テンプレートのランタイム実行に使用できる PHP コードを生成します。

You can manually compile a node tree to PHP code with the compile() method of an environment:

環境の compile() メソッドを使用して、ノード ツリーを手動で PHP コードにコンパイルできます。
1
$php = $twig->compile($nodes);

The generated template for a Hello {{ name }} template reads as follows (the actual output can differ depending on the version of Twig you are using):

Hello {{ name }} テンプレート用に生成されたテンプレートは次のようになります (実際の出力は、使用している Twig のバージョンによって異なる場合があります)。
1
2
3
4
5
6
7
8
9
10
11
12
/* 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
}

Note

ノート

The default compiler (\Twig\Compiler) can be changed by calling the setCompiler() method:

setCompiler() メソッドを呼び出すことで、デフォルトのコンパイラ (\Twig\Compiler) を変更できます。
1
$twig->setCompiler($compiler);