Шаблонизатор VMX::Template

Материал из YourcmcWiki
Версия от 17:17, 3 апреля 2011; VitaliyFilippov (обсуждение | вклад)

Это снимок страницы. Он включает старые, но не удалённые версии шаблонов и изображений.
Перейти к: навигация, поиск

Данный модуль представляет собой новую версию VMX::Template, построенную на некоторых новых идеях, ликвидировавшую безобразие и legacy-код, накопленный в старой версии, однако сохранившую высокую производительность и простоту.

Есть PHP-версия и Perl-версия шаблонизатора. Реализация, естественно, несколько отличается по причине различий языков — например, в Perl’е для кэширования кода используются coderef’ы, а в PHP предполагается, что кэшированием занимается какой-нибудь XCache или eAccelerator, ибо там сохранить coderef между запросами, по-видимому, невозможно.

Развивается то одна, то другая, в зависимости от проекта, над которым я работаю в моменте.

Также есть простенький (и кривоватенький) файл настроек синтаксиса шаблонов для Midnight Commander'а: tpl.syntax.

Работаю над транслятором с Template::Toolkit на VMX::Template. (ибо TT — задрал, скотина!). Код транслятора основан на оригинальной Parse::Yapp-грамматике из комплекта поставки TT и находится по адресу: tt2vmx.

Про VMX::Template можно сказать «ох уж эти перлисты — что ни пишут, всё Template::Toolkit получается». Это к тому, что идея вообще-то схожая, но реализация гораздо проще и быстрее.

Идеи

Уйти от assign_vars(), assign_block_vars(). Передавать, как и в обычных движках, просто хеш с данными $vars. Как, например, в Template::Toolkit. При этом сохранить данные методы для совместимости.

Почистить синтаксис: ликвидировать «преобразования», «вложенный путь по переменной» (->key->index->key->и т. п.), специальный синтаксис для окончания SET, неочевидное обращение к счётчику block.#, tr_assign_* и т. п.

Переписать с нуля компилятор.

Добавить в употребление функции, но только самые необходимые.

Добавить обработку ошибок и диагностические сообщения.

Использование

Здесь можно прочитать об: использовании в PHP, использовании в Perl, различиях реализаций.

PHP

require_once 'template.php';
 
# Конструктор
$template = new VMXTemplate(array(
    'root'          => '.',        # директория с шаблонами
    'cache_dir'     => './cache',  # директория для кэширования компилированного кода шаблонов
    'print_error'   => true,       # если true, ошибки компиляции выводятся на STDOUT
    'raise_error'   => false,      # если true, при ошибке компиляции вызывается die()
    'reload'        => true,       # если false, шаблоны будут считываться с диска только 1 раз, и вызовов stat() происходить не будет
    'use_utf8'      => true,       # если true, использовать кодировку UTF-8 для строковых операций
    'begin_code'    => '<!--',     # маркер начала директивы кода
    'end_code'      => '-->',      # маркер конца директивы кода
    'eat_code_line' => true,       # (похоже на TT CHOMP) съедать "лишний" перевод строки, если в строке только директива?
    'begin_subst'   => '{',        # маркер начала подстановки выражения
    'end_subst'     => '}',        # маркер конца подстановки выражения
    'compiletime_functions' =>     # дополнительные компилируемые функции
        array('func' => callback), # хеш вида имя функции (в шаблонах) => callback,
                                   # которому передаются скомпилированные выражения всех аргументов
    # немного legacy, устаревшее:
    'wrapper'       => NULL,       # если равно чему-то, что можно вызвать, через это будет
                                   # пропущен вывод всех шаблонов ("глобальный фильтр")
    'strict_end'    => false,      # требовать <!-- END имя_блока --> после <!-- BEGIN имя_блока -->
));
 
# Присвоение одной переменной:
$template->vars("ключ", "значение");
 
# Присвоение кучи переменных:
$template->vars(array("ключ" => "значение", ...));
 
# Выполнение шаблона и получение результата:
# (возможно с передачей данных в шаблон)
$page = $template->parse('имя_файла.tpl' [, array("ключ" => "значение", ...)]);
 
# Выполнение именованного блока из файла:
$page = $template->exec_from('имя_файла.tpl', 'имя_блока' [, array("ключ" => "значение", ...)]);
 
# Выполнение кода из строки:
$page = $template->parse_inline('код' [, array("ключ" => "значение", ...)]);
 
# Выполнение именованного блока из кода (не рекомендуется, но возможно):
$page = $template->exec_from_inline('код', 'имя_блока' [, array("ключ" => "значение", ...)]);
 
# Очистка сохранённых данных для генерации ещё одной страницы:
$template->clear;

Perl

use VMX::Template;
 
# Конструктор
$template = new VMX::Template(
    'root'          => '.',        # директория с шаблонами
    'cache_dir'     => undef,      # директория для кэширования компилированного кода шаблонов
    'reload'        => 2,          # если 0, то шаблоны не будут перечитываться с диска, и вызовов stat() происходить не будет
                                   # если >0, то шаблоны будут перечитываться с диска не чаще чем раз в reload секунд
    'print_error'   => 1,          # если TRUE, ошибки компиляции попадают в вывод шаблона
    'raise_error'   => 0,          # если TRUE, при ошибке компиляции вызывается die()
    'use_utf8'      => undef,      # если TRUE, использовать "use utf8" на шаблонах
    'begin_code'    => '<!--',     # маркер начала директивы кода
    'end_code'      => '-->',      # маркер конца директивы кода
    'eat_code_line' => 1,          # (похоже на TT CHOMP) съедать "лишний" перевод строки, если в строке только директива?
    'begin_subst'   => '{',        # маркер начала подстановки выражения
    'end_subst'     => '}',        # маркер конца подстановки выражения
    'compiletime_functions' =>     # дополнительные компилируемые функции
        { 'func' => sub {} },      # хеш вида имя функции (в шаблонах) => coderef,
                                   # которому передаются скомпилированные выражения всех аргументов и первым - сам $template
    # немного legacy, устаревшее:
    'wrapper'       => undef,      # если coderef, через это будет пропущен вывод всех шаблонов ("глобальный фильтр")
    'strict_end'    => 0,          # требовать <!-- END имя_блока --> после <!-- BEGIN имя_блока -->
);
 
# Присвоение переменных:
$template->vars("ключ" => "значение", "ключ" => "значение", ...);
 
# Выполнения полностью аналогичны PHP:
$page = $template->parse('имя_файла.tpl' [, { "ключ" => "значение", ... }]);
$page = $template->exec_from('имя_файла.tpl', 'имя_блока' [, { "ключ" => "значение", ... }]);
$page = $template->parse_inline('код' [, { "ключ" => "значение", ... }]);
$page = $template->exec_from_inline('код', 'имя_блока' [, { "ключ" => "значение", ... }]);
 
# Очистка сохранённых данных для генерации ещё одной страницы:
$template->clear;

Различия

Кэширование работает по-разному.

В целом, общий смысл — сделать так, чтобы шаблоны было не стыдно вызывать много раз, как много раз за один запрос, так и в целом, при этом максимально использовать механизмы интерпретатора самого языка. Но механизмы для этого применяются разные. Основная причина различий следующая:

  • Perl: считается, что всё прогрессивное человечество уже давно использует mod_perl или другие способы запуска веб-приложений, при которых частых переинициализаций интерпретатора не происходит. Иными словами, никто больше не использует CGI. Таким образом, мы смело можем сохранить живой coderef (ссылку на функцию, или кому как больше нравится — анонимную функцию, замыкание, делегат) в промежутке между двумя запросами.
  • PHP: интерпретатор PHP инициализируется заново при обработке каждого HTTP-запроса. А живой coderef в промежутке между двумя инициализациями интерпретатора сохранить, видимо, невозможно.

В PHP также есть ещё одна проблема — в процессе выполнения невозможно добавить метод в класс без использования извращений типа classkit, а хочется, потому что сгенерированные из кода шаблона функции должны быть методами — они используют контекст класса Template.

Поэтому компилированный шаблон PHP-версии — это класс, производный от класса Template. Единожды за один HTTP-запрос он загружается в память, а при каждом вызове шаблона создаётся пустой объект этого класса, в него записывается ссылка на tpldata и поле parent, ссылающееся на родительский объект Template, и вызывается метод класса, соответствующий блоку шаблона (см. #Блоки).

Кроме кэширования классов в рамках запроса в PHP существует ещё две ступени:

  • Текст шаблонов кэшируется в XCache или eAccelerator, если таковые присутствуют, и не перезагружается с диска лишний раз. Если reload = false, лишними считаются все разы, кроме первого, даже если файл шаблона менялся.
  • Компилированный код шаблонов кэшируется в файлах на диске, и не компилируется лишний раз.

В Perl действие reload немного отличается — reload = 0 работает так же, как reload = false в PHP, но если reload > 0, то тексты шаблонов перезагружаются с диска при изменении, но не чаще, чем раз в reload секунд. В остальном всё проще — компилированный шаблон представляет собой просто хеш с набором анонимных функций, которые сохраняются в my-переменной пакета VMX::Template и вызываются при обращении к шаблону или его блокам. Также существует и файловый кэш компилированного кода.

Несколько различается действие use_utf8 = true.

  • Общий смысл — «мои шаблоны и страницы в кодировке UTF-8».
  • PHP: «использовать mb_str* функции для работы со строками в выражениях».
  • Perl: «я передаю в шаблон все переменные с флагом UTF-8 = On, их можно смело конкатенировать с UTF-ными частями шаблона». Если кто-то не знает, в Perl строки имеют на себе флаг UTF-8 = да или нет, и при конкатенации строки без флага со строкой с флагом строка без флага будет автоматически переведена в UTF-8 из кодировки, соответствующей текущей локали. Что означает двойное UTF-8-кодирование в случае, если строка на самом деле всё-таки в UTF-8, но просто на ней не установлен флаг.
    Для приведения всех переменных шаблона к UTF-8 можно использовать функцию utf8on() из VMX::Common (рекурсивный Encode::_utf8_on()).

Различается способ вывода ошибок при print_error = true.

  • Общий смысл — при print_error = true ошибки и предупреждения должны попасть на экран.
  • PHP: они просто выводятся print()'ами.
  • Perl: здесь так нельзя, потому что HTTP-заголовки сами могут и не отправиться, поэтому текст ошибок прицепляется к выводу шаблонизатора (возвращается вместе с результатом parse()).

Различаются аргументы, передаваемые в compiletime_functions.

  • PHP: просто список кода выражений всех аргументов вызова. Функция-компилятор вызывается вне контекста объекта.
  • Perl: тот же список + $self (объект VMX::Template) в качестве первого элемента.

Различается поведение функций сравнения.

  • PHP: EQ и т. п. без S/N — типозависимое сравнение.
  • Perl: EQ и т. п. без S/N эквивалентно строковому (Sxx).

Различается поведение некоторых функций работы с массивами и хешами.

  • KEYS — в PHP порядок ключей массива/хеша сохраняется, а в Perl — нет и принимаются только хеши. Обусловлено реализацией хешей в этих языках.
  • PAIRS — в PHP порядок ключей сохраняется, в Perl-версии ключи будут отсортированы по имени.
  • RANGE — в Perl-версии принимает буквенные аргументы (A..Z = весь алфавит).
  • IS_ARRAY — в PHP-версии не проверяется, а не является ли он при этом хэшем, ибо трудоёмко (надо проверить, численные ли все ключи).
  • AGET и HGET в PHP идентичны GET.
  • ARRAY_MERGE: под Perl — только массивы (не хеши), под PHP — любые массивы.
  • DUMP — это Dumper в Perl’е и var_dump в PHP.

PHP-версия не зависит ни от чего (кроме PHP 5), а Perl-версия зависит от VMX::Common.

В PHP-версии в шаблоны не включаются C-подобные «прагмы» #line, а в текст ошибок не включается имя файла шаблона и строка. Ибо решил — раз уж #line не поддерживается, нечего на строки заморачиваться.

Реализация

Шаблон — любой текст, в который местами включены директивы и/или подстановки.

Маркеры начала и конца директивы <!-- --> и подстановки { } могут быть заменены любыми другими. Если, например, вы привыкли к TT, можно установить [% %]. Маркеры подстановки можно вообще не задавать — тогда для них используются маркеры директив.

  • Подстановка — любое выражение, состоящее из переменных {a.b.0.c} и вызовов функций {eq(a.b.0.c, 'hello world')}.
  • Директивы — это FOR, IF, END и прочие, либо тоже выражение. Разница между выражением в директиве и выражением в подстановке проявляется, если маркеры подстановки заданы — в этом случае подстановки вычисляют выражение и подставляют результат в выходной поток, а директивы вычисляют выражение и никуда его не подставляют — игнорируют. Исключение из этого правила: функции подстановки (см. Включения) подставляется в выходной поток всегда, и чтобы игнорировать результат включения шаблона, нужно явно указать void <!-- void include(...) -->.

Путь к переменной теперь может включать в себя числа. Это будут обращения к элементам массивов, в то время как всё остальное — обращения к элементам хешей.

Имена переменных регистрозависимы, имена встроенных функций и названия директив (BEGIN, END и т. п.) — регистронезависимы. Имена методов объектов, переданных в переменных, регистрозависимы.

Итак, <!-- FOR x = y --> — директива кода, {a.b.0.c} — подстановка выражения. Комментарии: <!--# комментарий -->

Циклы

Вне блока {block} будет иметь значение ARRAY(0x…), то есть массив всех итераций блока block, а {block.0} будет иметь значение HASH(0x…), то есть первую итерацию блока block.

<!-- BEGIN block -->

Теперь, внутри блока {block} теперь будет иметь значение HASH(0x…), то есть уже значение текущей итерации блока block, а {block.#} будет иметь значением номер текущей итерации блока, отсчитываемый с 0, а не с 1, как в старой версии.

<!-- END block -->

На <!-- END другоеимя --> после <!-- BEGIN block --> при strict_end = true шаблонизатор выдаст ошибку, «ибо нефиг» (c). Если block в хеше данных — не массив, а хеш — это значит, что итерация у блока только одна, и тогда <!-- BEGIN block --> работает как for($expression) {} в Perl никак.

BEGIN ... END — это циклы в «старом стиле». А можно использовать и TT-подобный, обычно более удобный:

<!-- FOR var = expression -->
...
<!-- END -->

Причём, если expression ::= block, то var может быть само block'ом. Это, по сути, и есть то, что делает BEGIN: <!-- BEGIN block --> эквивалентно <!-- FOR block = block -->. Предыдущее значение переменной цикла после выхода из цикла всегда восстанавливается.

К номеру итерации можно обратиться через {var#}.

Функции

Операторов нет, фильтров нет, есть функции. Пример:

<!-- IF OR(function(block.key1),AND(block.key2,block.key3)) -->

Почему? Тут всё просто — основываясь на предположении, что длинные выражения в шаблонах нужны очень редко, было лениво писать нормальную грамматику для разбора обычных выражений. Почему они нужны редко? Да просто минимум логики в шаблонах — признак хороших шаблонов. А функции покрывают сразу и выражения, и «фильтры», и методы объектов.

Синтаксис вызова функции нескольких аргументов:

<!-- function(block.key, 0, "abc") -->

Подстановка:

{function(block.key, 0, "abc")}

Синтаксис вызова функции одного аргумента:

<!-- function(block.key) -->
<!-- function block.key -->
{block.key/s}
{s block.key}

Синтаксис вызова метода объекта:

{object.method()}
{object.method(arg1, arg2)}
{call(object, "method")}
{call(object, "method", arg1, arg2)}

Последние два применения — как нетрудно заметить, обращение к функции call() и служат для вызова метода по вычисляемому имени.

Цепочки вызовов методов типа object.method().another_method() не поддерживаются, ибо к ним без сохранения звеньев нервно относится даже сам PHP.

IF

Условный вывод:

<!-- IF function(block.key) --><!-- ELSEIF ... --><!-- END -->
<!-- IF NOT block.key -->...<!-- END -->                      

ELSIF эквивалентно ELSE IF и ELSEIF.

SET

Запись значения переменной:

<!-- SET block.key -->...<!-- END --></nowiki>
<!-- SET block.key = выражение -->

Включения

Включение другого шаблона также осталось:

<!-- INCLUDE another-file.tpl -->
<!-- INCLUDE "another-file.tpl" -->

По «динамическому» имени шаблона включение производится функциями включения. Как несложно заметить, вторая строка — как раз вызов функции.

Блоки

Блок — это часть шаблона, выделенная в отдельную «функцию», хорошо кэшируемая и предназначенная для повторного вызова из других мест. Покрывает сразу несколько вещей — «блоки», «макросы» и «обёртки» из TT. Да-да, TT славится бессмысленным дублированием функционала.

Наши блоки имеют несколько преимуществ:

  • блоки, определённые в одном шаблоне, можно смело вызывать из других по имени файла + имени блока!
  • блок можно определить просто как некоторое выражение.
  • блоки хорошо кэшируются — с VMX::Template вы не испытаете разочарования, если вызовете какой-нибудь блок 1000 раз. В отличие от TT.

Блоки в шаблоне не могут быть вложенными, а циклы, SET и прочие вещи, их оборачивающие, не имеют на них никакого влияния. После компиляции блоки просто вырезаются и преобразуются в отдельные функции PHP/Perl’а.

<!-- BLOCK имя_блока -->
...код...
<!-- END -->

или

<!-- BLOCK имя_блока = выражение -->

Вместо слова BLOCK можно также использовать слово FUNCTION или MACRO.

Вызывать блок из шаблона следует с помощью функций EXEC, EXEC_FROM. Вызывать блок из кода следует с помощью функций #EXEC_FROM_INLINE. Также см. #Использование.

Функции

Функции используются в выражениях как ФУНКЦИЯ(АРГУМЕНТ, АРГУМЕНТ, ...) или как ФУНКЦИЯ (пробел) ОДИН_АРГУМЕНТ. Вместо запятой ", " можно также использовать «=>», например HASH(КЛЮЧ => ЗНАЧЕНИЕ, КЛЮЧ => ЗНАЧЕНИЕ). Синтаксической разницы между ", " и «=>» никакой нет.

Существующие функции перечислены ниже. Через «=» в подзаголовках указываются синонимы функций.

Расширяемость в области функций:

Run-time функции
В качестве функции можно использовать метод переданного в хеше данных объекта. В «функцию» можно вынести и блок кода из шаблона — см. #Блоки. Оно хорошо кэшируется.
Compile-time функции
При создании объекта шаблона можно передать параметр compiletime_functions, равный хешу, в котором ключи — имена дополнительных функций, а значения — любые coderef’ы (Perl) или callable (PHP). Эти функции вызываются в контексте объекта шаблона с параметрами, равными коду для вычисления соответствующего аргумента, и должны возвращать код для вычисления результата. То есть, они выполняются на этапе компиляции.

Note.svg Первое, что обычно нужно — это S(), H(), T(), Q(), I(), то есть «фильтры» для различных преобразований строки:

  • S() — это htmlspecialchars(), экранирует HTML/XML-спецсимволы в строках.
  • H() — удаляет все HTML-теги, кроме «безопасных».
  • T() — удаляет все HTML-теги.
  • Q() — это addslashes(), экранирует строки для использования, например, в JS.
  • I() — преобразует значение к целому числу.

Числа, логические операции

OR, AND, NOT

Логические ИЛИ, И, НЕ, действующие аналогично Perl операторам ||, &&, !.

ADD, SUB, MUL, DIV, MOD

Арифметические операции + — * / %.

LOG

Логарифм.

EVEN, ODD

Истина в случае, если аргумент чётный или нечётный соответственно.

INT=I=INTVAL

Преобразование к целому числу.

EQ, NE, GT, LT, GE, LE

Сравнения == != > < >= <= аргументов как строк (Perl) или типо-зависимое сравнение (PHP). В PHP если хотя бы один из аргументов численный, сравниваются они как числа.

SEQ, SNE, SGT, SLT, SGE, SLE

Аргументы сравниваются всегда как строки.

NEQ, NNE, NGT, NLT, NGE, NLE

Аргументы сравниваются всегда как числа.

YESNO

Тернарный оператор $1 ? $2 : $3.

Строки

LC=LOWER=LOWERCASE, UC=UPPER=UPPERCASE

Нижний и верхний регистр.

LCFIRST, UCFIRST

Преобразование первого символа строки в нижний и верхний регистр соответственно.

Q=QUOTE=ADDSLASHES, SQ=SQL_QUOTE, REQUOTE=RE_QUOTE=PREG_QUOTE

Экранирование символов " ' \ и перевода строки бэкслэшем — quote(строка).

Экранирование символа " удвоением — sql_quote(строка). (актуально также для CSV)

Экранирование символов, являющихся специальными в регулярных выражениях — re_quote(строка). (см. perldoc perlre).

URI_QUOTE=URIQUOTE=URLENCODE

URL-кодирование строки (URI::Escape в Perl и urlencode() в PHP).

REPLACE, STR_REPLACE

Замена Perl- (соответственно PCRE- в PHP-версии) регулярного выражения в строке — replace(RegExp, замена, строка).

Замена подстроки в строке — str_replace(искомое, замена, строка).

STRLEN

Длина строки в символах.

SUBSTR=SUBSTRING

Стандартная (для всех, кроме жавистов) функция подстроки — substr(строка, начало, длина), или substr(строка, начало). Причём начало и длина могут быть отрицательными, тогда они считаются относительно длины строки.

TRIM

Удаление пробелов из начала и конца строки.

SPLIT

Разделение строки по регулярному выражению и лимиту — split(RegExp, аргумент, лимит). Лимит необязателен. (см. perldoc -f split)

S=HTML=HTMLSPECIALCHARS, T=STRIP, H=STRIP_UNSAFE, NL2BR

Преобразование символов < > & " ' в HTML-сущности.

Удаление всех HTML/XML тегов.

Удаление только «небезопасных» HTML-тегов.

Преобразование переводов строк (\n) в HTML-тег <br />.

CONCAT, JOIN=IMPLODE

Конкатенация всех своих аргументов — concat(аргументы). Конкатенирует также все элементы всех переданных массивов.

Конкатенация элементов массива через разделитель — join(строка, аргументы). Конкатенирует также все элементы всех переданных массивов.

SUBST, SPRINTF, STRFTIME

Подстановка на места подстрок вида $ЧИСЛО соответствующих параметров функции или элементов переданного массива — subst(строка, $1, $2, …).

Sprintf — он и в Африке sprintf.

Форматирование даты и/или времени с помощью функции strftime — strftime(формат, дата [, часть_даты]). Формат strftime’овский (например, «%d %b %Y»). Дата может передаваться как один или два аргумента, если два — они конкатенируются через пробел. Далее дата разбирается способом, похожим на wfTimestamp() в MediaWiki. Принимается следующее:

  • UNIX время.
  • Времена типа MySQL DATE, MySQL DATETIME, EXIF, ISO 8601, MediaWiki, и любые другие, подпадающие под следующий формат: 1 группа из 4 или более цифр (год) и 2 (месяц, день) или 5 (месяц, день, часы, минуты, секунды) групп по 2 цифры, разделённые любыми нецифровыми символами и в конце — опционально временная зона — 2 цифры, предварённые пробелом, плюсом или минусом. Короче говоря,
    ^\D*(\d{4,})\D*(\d{2})\D*(\d{2})\D*(?:(\d{2})\D*(\d{2})\D*(\d{2})\D*([\+\- ]\d{2}\D*)?)?$
  • Оракловский формат даты-времени: ДД-Мес-ГГ[ГГ] ЧЧ.ММ.СС.
  • RFC 822.

STRLIMIT=TRUNCATE

Ограничение длины строки str максимальной длиной len — strlimit(str, len, dots = "..."). Если строка превышает заданную длину, она обрезается предпочтительно по пробелу или Tab’у, а в конец добавляется dots или по умолчанию "...", если аргумент dots не передаётся.

Массивы и хеши

HASH

Создание хэша из всех аргументов.

Соответственно в хеше аргументы идут парами КЛЮЧ => ЗНАЧЕНИЕ, КЛЮЧ => ЗНАЧЕНИЕ и т. п.

KEYS, HASH_KEYS, ARRAY_KEYS

Массив ключей хэша. Понятное дело, в PHP их порядок сохраняется, а в Perl — нет.

SORT

Сортировка массива по значениям.

PAIRS

Массив хэшей вида { key => ключ, value => значение } для хэша, в случае Perl ключи будут отсортированы по имени.

ARRAY, RANGE

Создание массива.

Диапазон от A до B — range(A, B).

IS_ARRAY

Проверка, является ли аргумент массивом. В PHP-версии не проверяется, а не является ли он при этом хэшем, ибо трудоёмко.

COUNT, SUBARRAY=ARRAY_SLICE, SUBARRAY_DIVMOD

Количество элементов массива, или 0, если аргумент — не массив — count(аргумент).

Аналог функции array_slice из PHP.

Выбор из массива каждого div’того элемента, начиная с номера mod или нуля по умолчанию — subarray_divmod(массив, div, mod).

GET, AGET, HGET

Получение элемента массива/хэша по «динамическому» ключу. По-моему, это лучше, чем зюки-хрюки Template Toolkit’а: hash.${hash2.$key} и т. п.

GET(откуда, что) автоматически решает, «откуда» — это массив или хеш, AGET служит только для массивов, а HGET только для хешей. В PHP-версии все три идентичны.

GET(что) — получение значения переменной верхнего уровня.

Стоит отметить, что PHP-версия для выражений, подобных get(function_that_returns_array(), 'array_key') вместо запрещённого синтаксисом PHP выражения (function_that_returns_array()['array_key']) автоматически использует выражение вида self::exec_get(function_that_returns_array(), 'array_key').

SET

SET(куда, что) — присваивание «куда» значения «что». Уравнения, понятное дело, не решает, то есть, как и обычно, присваивать можно только lvalue :)

ARRAY_MERGE

Слить массивы в один. Под Perl — только массивы (не хеши), под PHP — любые массивы.

SHIFT, POP, UNSHIFT, PUSH

Вынуть элемент из начала массива, вынуть из конца, добавить в начало — unshift(array, value), добавить в конец — push(array, value).

Включения

Сюда относятся функции выполнения других шаблонов и/или их блоков. Во все эти функции можно передавать «данные» (tpldata) либо с помощью создания хеша функцией hash(), либо просто передачей аргументов как КЛЮЧ => ЗНАЧЕНИЕ, ....

Также имеют особенность: результат этих функций подставляется даже при использовании в директивах. То есть, например, если маркеры директив <!-- -->, а подстановок { }, то <!-- include(...) --> всё равно будет подставлено. Игнорировать результат нужно явно: <!-- void include(...) -->.

PARSE=INCLUDE=PROCESS

Включение другого шаблона.

parse('имя файла')
parse('имя файла', hash( ключ => значение, ... ))
parse('имя файла', ключ => значение, ...)

PARSE_INLINE=INCLUDE_INLINE=PROCESS_INLINE

Включение кода не из файла, а просто из строки — parse_inline('код шаблона'[, аргументы]).

EXEC

Включение блока из текущего шаблона — exec('имя блока'[, аргументы]).

EXEC_FROM

Включение блока из другого шаблона — exec_from('имя файла', 'имя блока'[, аргументы]).

EXEC_FROM_INLINE

Сие не рекомендуется, но можно вызывать и функции из кода из строки — exec_from_inline('код шаблона', 'имя блока'[, аргументы]).

Прочее

VOID

Вычислить аргумент и вернуть пустую строку. Потенциально нужно для игнорирования результата, ибо все возвращаемые значения радостно подставляются в выходной поток.

DUMP=VAR_DUMP

Вывод всех данных из структуры — Dumper в Perl’е и var_dump в PHP.

JSON

Форматирование любой структуры данных в формат JSON.

CALL

Вызов метода объекта по «динамическому» имени — call(varref, method_name, arg1, arg2, arg3, ...).

MAP

Применение функции, имя которой передано как первый аргумент, ко всем переданным аргументам и элементам всех переданных массивов — map(«имя_функции», аргументы).