hacking.rst 5.2KB

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