a Sensio Labs Product

Гибкий, быстрый и безопасный
шаблонизатор для PHP

Модифицируем Twig

Twig очень просто расширить и вы легко можете модифицировать его. Имейте в виду, что вероятно лучше попытаться создать новое расширение, а не модифицировать ядро шаблонизатора. Этот раздел также будет полезен тем, кто хочет разобраться в том, как устроен Twig.

Как устроен Twig?

Получение шаблонов Twig условно состоит из четырех этапов:

  • Загрузка шаблона: Если шаблон уже откомпилирован, он загружается и переходим на последний этап, иначе:

    • Во-первых, лексический анализатор разбивает шаблон на маленькие кусочки (токены) для упрощения обработки;

    • Затем, парсер конвертирует последовательность токенов в дерево узлов (Абстрактное синтаксическое дерево);

    • В конечном итоге компилятор преобразует АСД в PHP код;

  • Обработка шаблона: происходит при вызове метода display() для скомпилированного шаблона и передачи ему переменных.

Лексический анализатор

Задача лексического анализатора разбить исходный код на последовательность токенов (каждый токен имеет класс Token, а их последовательность - Twig_TokenStream). По-умолчанию, лексический анализатор знает о девяти типах токенов:

  • Twig_Token::TEXT_TYPE
  • Twig_Token::BLOCK_START_TYPE
  • Twig_Token::VAR_START_TYPE
  • Twig_Token::BLOCK_END_TYPE
  • Twig_Token::VAR_END_TYPE
  • Twig_Token::NAME_TYPE
  • Twig_Token::NUMBER_TYPE
  • Twig_Token::STRING_TYPE
  • Twig_Token::OPERATOR_TYPE
  • Twig_Token::EOF_TYPE

Вы можете вручную преобразовать исходный код в последовательность токенов вызвав метод tokenize():

$stream = $twig->tokenize($source, $identifier);

Так как последовательность токенов имеет метод __toString(), вы можете использовать echo для вывода результата в браузер:

echo $stream."\n";

Последовательность токенов для шаблона Hello {{ name }}:

TEXT_TYPE(Hello )
VAR_START_TYPE()
NAME_TYPE(name)
VAR_END_TYPE()
EOF_TYPE()

Вы можете изменить лексический анализатор используемый по-умолчанию (Twig_Lexer) на свой используя метод setLexer():

$twig->setLexer($lexer);

Класс лексического анализатора должен реализовывать интерфейс Twig_LexerInterface:

interface Twig_LexerInterface
{
  /**
   * Выделяет токены в исходном коде.
   *
   * @param  string $code     Исходный код
   * @param  string $filename Уникальный идентификатор исходного кода
   *
   * @return Twig_TokenStream Последовательность токенов
   */
  public function tokenize($code, $filename = 'n/a');
}

Лексический анализатор (парсер)

Парсер конвертирует последовательность токенов в (АСД), или дерево узлов (класс Twig_Node_Module). По умолчанию определены основные узлы: for, if и узлы выражений.

Вы можете вручную конвертировать последовательность токенов в дерево узлов, вызвав метод parse():

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

Использовав echo, вы сможете посмотреть на результирующее дерево:

echo $nodes."\n";

Вот что получиться для шалона Hello {{ name }}:

Twig_Node_Module(
  Twig_Node_Text(Hello )
  Twig_Node_Print(
    Twig_Node_Expression_Name(name)
  )
)

Парсер по-умолчанию (Twig_TokenParser) может быть заменен с помощью метода setParser():

$twig->setParser($parser);

Парсеры Twig должны реализовывать интерфейс Twig_ParserInterface:

interface Twig_ParserInterface
{
  /**
   * Конвертирует последовательность токенов в дерево.
   *
   * @param  Twig_TokenStream $stream Последовательность токенов
   *
   * @return Twig_Node_Module Узел дерева
   */
  public function parser(Twig_TokenStream $code);
}

Компилятор

Последний шаг это компилятор. Он принимает дерево узлов и генерирует PHP код, готовый для рендеринга. По-умолчанию компилятор генерирует классы для облегчения наследования шаблонов.

Вы можете вызвать компиляцию вручную, с помощью метода compile():

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

Метод compile() вернет исходный код PHP, представляющий узлы.

Для шаблона Hello {{ name }} получиться следующее:

/* Hello {{ name }} */
class __TwigTemplate_1121b6f109fe93ebe8c6e22e3712bceb extends Twig_Template
{
  public function display($context)
  {
    $this->env->initRuntime();
 
    // строка 1
    echo "Hello ";
    echo (isset($context['name']) ? $context['name'] : null);
  }
}

Так же как лексический и синтаксический анализатор, компилятор (Twig_Compiler) может быть изменен методом setCompiler():

$twig->setCompiler($compiler);

Компилятор Twig должен реализовывать интерфейс Twig_CompilerInterface:

interface Twig_CompilerInterface
{
  /**
   * Собирает узел.
   *
   * @param  Twig_Node $node Узел для сборки
   *
   * @return Twig_Compiler Компилятор
   */
  public function compile(Twig_Node $node);
 
  /**
   * Получаем PHP код, после компиляции.
   *
   * @return string PHP код
   */
  public function getSource();
}