Twig очень просто расширить и вы легко можете модифицировать его. Имейте в виду, что вероятно лучше попытаться создать новое расширение, а не модифицировать ядро шаблонизатора. Этот раздел также будет полезен тем, кто хочет разобраться в том, как устроен Twig.
Получение шаблонов Twig условно состоит из четырех этапов:
Загрузка шаблона: Если шаблон уже откомпилирован, он загружается и переходим на последний этап, иначе:
Во-первых, лексический анализатор разбивает шаблон на маленькие кусочки (токены) для упрощения обработки;
Затем, парсер конвертирует последовательность токенов в дерево узлов (Абстрактное синтаксическое дерево);
В конечном итоге компилятор преобразует АСД в PHP код;
Обработка шаблона: происходит при вызове метода display() для скомпилированного шаблона и передачи ему переменных.
Задача лексического анализатора разбить исходный код на последовательность токенов (каждый токен имеет класс Token, а их последовательность - Twig_TokenStream). По-умолчанию, лексический анализатор знает о девяти типах токенов:
Twig_Token::TEXT_TYPETwig_Token::BLOCK_START_TYPETwig_Token::VAR_START_TYPETwig_Token::BLOCK_END_TYPETwig_Token::VAR_END_TYPETwig_Token::NAME_TYPETwig_Token::NUMBER_TYPETwig_Token::STRING_TYPETwig_Token::OPERATOR_TYPETwig_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(); }