]>
Commit | Line | Data |
---|---|---|
4f5b44bd NL |
1 | Twig Internals |
2 | ============== | |
3 | ||
4 | Twig is very extensible and you can easily hack it. Keep in mind that you | |
5 | should probably try to create an extension before hacking the core, as most | |
6 | features and enhancements can be done with extensions. This chapter is also | |
7 | useful for people who want to understand how Twig works under the hood. | |
8 | ||
9 | How Twig works? | |
10 | --------------- | |
11 | ||
12 | The rendering of a Twig template can be summarized into four key steps: | |
13 | ||
14 | * **Load** the template: If the template is already compiled, load it and go | |
15 | to the *evaluation* step, otherwise: | |
16 | ||
17 | * First, the **lexer** tokenizes the template source code into small pieces | |
18 | for easier processing; | |
19 | * Then, the **parser** converts the token stream into a meaningful tree | |
20 | of nodes (the Abstract Syntax Tree); | |
21 | * Eventually, the *compiler* transforms the AST into PHP code; | |
22 | ||
23 | * **Evaluate** the template: It basically means calling the ``display()`` | |
24 | method of the compiled template and passing it the context. | |
25 | ||
26 | The Lexer | |
27 | --------- | |
28 | ||
29 | The lexer tokenizes a template source code into a token stream (each token is | |
30 | an instance of ``Twig_Token``, and the stream is an instance of | |
31 | ``Twig_TokenStream``). The default lexer recognizes 13 different token types: | |
32 | ||
33 | * ``Twig_Token::BLOCK_START_TYPE``, ``Twig_Token::BLOCK_END_TYPE``: Delimiters for blocks (``{% %}``) | |
34 | * ``Twig_Token::VAR_START_TYPE``, ``Twig_Token::VAR_END_TYPE``: Delimiters for variables (``{{ }}``) | |
35 | * ``Twig_Token::TEXT_TYPE``: A text outside an expression; | |
36 | * ``Twig_Token::NAME_TYPE``: A name in an expression; | |
37 | * ``Twig_Token::NUMBER_TYPE``: A number in an expression; | |
38 | * ``Twig_Token::STRING_TYPE``: A string in an expression; | |
39 | * ``Twig_Token::OPERATOR_TYPE``: An operator; | |
40 | * ``Twig_Token::PUNCTUATION_TYPE``: A punctuation sign; | |
41 | * ``Twig_Token::INTERPOLATION_START_TYPE``, ``Twig_Token::INTERPOLATION_END_TYPE`` (as of Twig 1.5): Delimiters for string interpolation; | |
42 | * ``Twig_Token::EOF_TYPE``: Ends of template. | |
43 | ||
44 | You can manually convert a source code into a token stream by calling the | |
45 | ``tokenize()`` of an environment:: | |
46 | ||
47 | $stream = $twig->tokenize($source, $identifier); | |
48 | ||
49 | As the stream has a ``__toString()`` method, you can have a textual | |
50 | representation of it by echoing the object:: | |
51 | ||
52 | echo $stream."\n"; | |
53 | ||
54 | Here is the output for the ``Hello {{ name }}`` template: | |
55 | ||
56 | .. code-block:: text | |
57 | ||
58 | TEXT_TYPE(Hello ) | |
59 | VAR_START_TYPE() | |
60 | NAME_TYPE(name) | |
61 | VAR_END_TYPE() | |
62 | EOF_TYPE() | |
63 | ||
64 | .. note:: | |
65 | ||
66 | You can change the default lexer use by Twig (``Twig_Lexer``) by calling | |
67 | the ``setLexer()`` method:: | |
68 | ||
69 | $twig->setLexer($lexer); | |
70 | ||
71 | The Parser | |
72 | ---------- | |
73 | ||
74 | The parser converts the token stream into an AST (Abstract Syntax Tree), or a | |
75 | node tree (an instance of ``Twig_Node_Module``). The core extension defines | |
76 | the basic nodes like: ``for``, ``if``, ... and the expression nodes. | |
77 | ||
78 | You can manually convert a token stream into a node tree by calling the | |
79 | ``parse()`` method of an environment:: | |
80 | ||
81 | $nodes = $twig->parse($stream); | |
82 | ||
83 | Echoing the node object gives you a nice representation of the tree:: | |
84 | ||
85 | echo $nodes."\n"; | |
86 | ||
87 | Here is the output for the ``Hello {{ name }}`` template: | |
88 | ||
89 | .. code-block:: text | |
90 | ||
91 | Twig_Node_Module( | |
92 | Twig_Node_Text(Hello ) | |
93 | Twig_Node_Print( | |
94 | Twig_Node_Expression_Name(name) | |
95 | ) | |
96 | ) | |
97 | ||
98 | .. note:: | |
99 | ||
100 | The default parser (``Twig_TokenParser``) can be also changed by calling the | |
101 | ``setParser()`` method:: | |
102 | ||
103 | $twig->setParser($parser); | |
104 | ||
105 | The Compiler | |
106 | ------------ | |
107 | ||
108 | The last step is done by the compiler. It takes a node tree as an input and | |
109 | generates PHP code usable for runtime execution of the template. | |
110 | ||
111 | You can call the compiler by hand with the ``compile()`` method of an | |
112 | environment:: | |
113 | ||
114 | $php = $twig->compile($nodes); | |
115 | ||
116 | The ``compile()`` method returns the PHP source code representing the node. | |
117 | ||
118 | The generated template for a ``Hello {{ name }}`` template reads as follows | |
119 | (the actual output can differ depending on the version of Twig you are | |
120 | using):: | |
121 | ||
122 | /* Hello {{ name }} */ | |
123 | class __TwigTemplate_1121b6f109fe93ebe8c6e22e3712bceb extends Twig_Template | |
124 | { | |
125 | protected function doDisplay(array $context, array $blocks = array()) | |
126 | { | |
127 | // line 1 | |
128 | echo "Hello "; | |
129 | echo twig_escape_filter($this->env, $this->getContext($context, "name"), "ndex", null, true); | |
130 | } | |
131 | ||
132 | // some more code | |
133 | } | |
134 | ||
135 | .. note:: | |
136 | ||
137 | As for the lexer and the parser, the default compiler (``Twig_Compiler``) can | |
138 | be changed by calling the ``setCompiler()`` method:: | |
139 | ||
140 | $twig->setCompiler($compiler); |