Изменения

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

10 713 байтов добавлено, 00:07, 7 января 2011
м
Нет описания правки
Добавить обработку ошибок и диагностические сообщения.
== Использование (== Здесь можно прочитать об: использовании в PHP) , использовании в Perl, различиях реализаций. === PHP ===
<source lang="php">
$template->clear;
</source>
 
=== Perl ===
 
=== Различия ===
 
'''Кэширование работает по-разному.'''
 
В целом, общий смысл — сделать так, чтобы шаблоны было не стыдно вызывать много раз, как много раз за один запрос, так и в целом, при этом максимально использовать механизмы интерпретатора самого языка. Но механизмы для этого применяются разные. Основная причина следующая:
 
* Perl: считается, что всё прогрессивное человечество уже давно использует <tt>mod_perl</tt> или [[Платформы для запуска Perl веб-приложений|другие способы запуска веб-приложений]], при которых частых переинициализаций интерпретатора не происходит. Иными словами, ''никто больше не использует CGI''. Таким образом, мы смело можем сохранить живой coderef (ссылку на функцию, или кому как больше нравится — анонимную функцию, замыкание, делегат) в промежутке между двумя запросами.
* PHP: интерпретатор PHP инициализируется заново при обработке каждого HTTP-запроса. А coderef в промежутке между двумя инициализациями интерпретатора сохранить, видимо, невозможно.
 
В PHP также есть ещё одна проблема — в процессе выполнения невозможно добавить метод в класс без использования извращений типа [http://pecl.php.net/package/classkit classkit], а хочется, потому что сгенерированные из кода шаблона функции должны быть методами — они используют контекст класса Template.
 
Поэтому компилированный шаблон PHP-версии — это класс, производный от класса Template. Единожды за один HTTP-запрос он загружается в память, а при каждом вызове шаблона создаётся пустой объект этого класса, в него записывается ссылка на <tt>tpldata</tt> и поле <tt>parent</tt>, ссылающееся на родительский объект Template, и вызывается метод класса, соответствующий блоку шаблона (см. [[#Блоки]]).
 
Кроме кэширования классов в рамках запроса в PHP существует ещё две ступени:
* Текст шаблонов кэшируется в XCache или eAccelerator, если таковые присутствуют, и не перезагружается с диска лишний раз. Если <tt>reload = false</tt>, лишними считаются все разы, кроме первого, даже если файл шаблона менялся.
* Компилированный код шаблонов кэшируется в файлах на диске, и не компилируется лишний раз.
 
В Perl действие <tt>reload</tt> немного отличается — <tt>reload = 0</tt> работает так же, как <tt>reload = false</tt> в PHP, но если <tt>reload > 0</tt>, то тексты шаблонов перезагружаются с диска при изменении, но не чаще, чем раз в <tt>reload</tt> секунд. В остальном всё проще — компилированный шаблон представляет собой просто хеш с набором анонимных функций, которые сохраняются в my-переменной пакета VMX::Template и вызываются при обращении к шаблону или его блокам. Также существует и файловый кэш компилированного кода.
 
'''Несколько различается действие <tt>use_utf8 = true</tt>.'''
 
* Общий смысл — «мои шаблоны и страницы в кодировке UTF-8».
* PHP: «использовать mb_str* функции для работы со строками в выражениях».
* Perl: «я передаю в шаблон все переменные с флагом UTF-8 = On, их можно смело конкатенировать с UTF-ными частями шаблона». Если кто-то не знает, в Perl строки имеют на себе флаг UTF-8 = да или нет, и при конкатенации строки без флага со строкой с флагом строка без флага будет автоматически переведена в UTF-8 из кодировки, соответствующей текущей локали. Что означает двойное UTF-8-кодирование в случае, если строка на самом деле всё-таки в UTF-8, но просто на ней не установлен флаг.
*: Для приведения всех переменных шаблона к UTF-8 можно использовать функцию <tt>utf8on()</tt> из [{{SVN|vitaphoto/branch/solstice/lib-sway/VMX/Common.pm}} VMX::Common] (рекурсивный <tt>Encode::_utf8_on()</tt>).
 
'''Различается способ вывода ошибок при <tt>print_error = true</tt>.'''
 
* Общий смысл — при <tt>print_error = true</tt> ошибки и предупреждения должны попасть на экран.
* PHP: они просто выводятся print()'ами.
* Perl: здесь так нельзя, потому что HTTP-заголовки сами могут и не отправиться, поэтому текст ошибок прицепляется к выводу шаблонизатора (возвращается вместе с результатом <tt>parse()</tt>).
 
'''Различаются аргументы, передаваемые в <tt>compiletime_functions</tt>.'''
 
* PHP: просто список кода выражений всех аргументов вызова. Функция-компилятор вызывается вне контекста объекта.
* Perl: тот же список + <tt>$self</tt> (объект VMX::Template) в качестве первого элемента.
 
'''Различается поведение функций сравнения.'''
 
* PHP: EQ и т. п. без S/N — типозависимое сравнение.
* Perl: EQ и т. п. без S/N эквивалентно строковому (Sxx).
 
'''Различается поведение некоторых функций работы с массивами и хешами.'''
 
* KEYS — в PHP порядок ключей массива/хеша сохраняется, а в Perl — нет и принимаются только хеши. Обусловлено реализацией хешей в этих языках.
* EACH — в Perl-версии ключи будут отсортированы по имени.
* RANGE — в Perl-версии принимает буквенные аргументы (A..Z = весь алфавит).
* IS_ARRAY — в PHP-версии не проверяется, а не является ли он при этом хэшем, ибо трудоёмко (надо проверить, численные ли все ключи).
* AGET и HGET в PHP идентичны GET.
* ARRAY_MERGE: под Perl — только массивы (не хеши), под PHP — любые массивы.
* DUMP — это Dumper в Perl’е и var_dump в PHP.
== Реализация ==
;Compile-time функции: При создании объекта шаблона можно передать параметр <tt>compiletime_functions</tt>, равный хешу, в котором ключи — имена дополнительных функций, а значения — любые coderef’ы (Perl) или callable (PHP). Эти функции вызываются в контексте объекта шаблона с параметрами, равными '''коду для вычисления соответствующего аргумента''', и должны возвращать '''код для вычисления результата'''. То есть, они выполняются на этапе компиляции.
=== Числа, логические операции === ==== OR, AND, NOT ====
Логические ИЛИ, И, НЕ, действующие аналогично Perl операторам ||, &&, !.
==== ADD, SUB, MUL, DIV, MOD ==== Арифметические операции + — * / %. ==== LOG ==== Логарифм. ==== EVEN, ODD ====
Истина в случае, если аргумент чётный или нечётный соответственно.
==== INT=I, ADD, MUL, DIV, MOD, LOG =INTVAL ====
Преобразование к целому числу, арифметические операции и логарифм.
==== EQ, NE, SEQ, SNE, GT, LT, GE, LE, SGT, SLT, SGE, SLE ====
Действуют аналогично Perl операторам Сравнения == eq != > < >= <= gt lt ge leаргументов как строк (Perl) или типо-зависимое сравнение (PHP). В PHP если хотя бы один из аргументов численный, сравниваются они как числа.
В PHP-версии на данный момент такого много-безобразия нет==== SEQ, есть просто EQ NE GT LT GE LE. Хотя это и имеет свои минусы - если хотя бы один аргумент принимается PHP как численныйSNE, сравнение становится численным.SGT, SLT, SGE, SLE ====
=== COUNT, SUBARRAY=ARRAY_SLICE, SUBARRAY_DIVMOD ===Аргументы сравниваются всегда как строки.
Количество элементов массива==== NEQ, или 0NNE, если аргумент — не массив — count(аргумент).NGT, NLT, NGE, NLE ====
Аналог функции [http://php.net/manual/en/function.array-slice.php array_slice] из PHPАргументы сравниваются всегда как числа.
Выбор из массива каждого div’того элемента, начиная с номера mod или нуля по умолчанию — subarray_divmod(массив, div, mod).==== YESNO ====
=== ARRAY, HASH ===Тернарный оператор $1 ? $2 : $3.
Создание массива или хэша из всех атрибутов.=== Строки ===
Соответственно в хеше атрибуты идут парами КЛЮЧ==== LC=LOWER=LOWERCASE, ЗНАЧЕНИЕ, КЛЮЧ, ЗНАЧЕНИЕ и т.п. (специального синтаксиса "UC=UPPER=UPPERCASE ====>" нет).
=== SORT ===Нижний и верхний регистр.
Сортировка массива по значениям.==== Q=QUOTE=ADDSLASHES, SQ=SQL_QUOTE, REQUOTE=RE_QUOTE=PREG_QUOTE ====
=== ARRAY_MERGE ===Экранирование символов " ' \ и перевода строки бэкслэшем — quote(строка).
Слить массивы в один. Под Perl — только массивы Экранирование символа " удвоением - sql_quote(не хешистрока), под PHP — любые массивы.(актуально также для [[rupedia:CSV|CSV]])
=== GETЭкранирование символов, AGET, HGET ===являющихся специальными в регулярных выражениях — re_quote(строка). (см. [http://perldoc.perl.org/perlre.html perldoc perlre]).
Получение элемента массива/хэша по «динамическому» ключу. По-моему, это лучше, чем зюки-хрюки Template Toolkit’а: <tt>hash.${hash2.$key}</tt> и т. п.=== URI_QUOTE=URIQUOTE=URLENCODE ===
<tt>GETURL-кодирование строки (откуда, что)<{{CPAN|URI::Escape}} в Perl и [http:/tt> автоматически решает, «откуда» — это массив или хеш, AGET служит только для массивов, а HGET только для хешей/php. В net/manual/en/function.urlencode.php urlencode()] в PHP-версии все три идентичны).
<tt>GET(что)</tt> — получение значения переменной верхнего уровня.==== REPLACE, STR_REPLACE ====
=== MAP ===Замена Perl- (соответственно PCRE- в PHP-версии) регулярного выражения в строке — replace(RegExp, замена, строка).
Применение функцииЗамена подстроки в строке - str_replace(искомое, имя которой передано как первый аргумент, ко всем переданным аргументам и элементам всех переданных массивов — map(«имя_функции»замена, аргументыстрока).
=== LC=LOWERSTRLEN =LOWERCASE, UC=UPPER=UPPERCASE ===
Нижний и верхний регистрДлина строки ''в символах''.
=== STRLIMIT = SUBSTR=SUBSTRING ====
Ограничение длины строки s максимальной длиной l — strlimitСтандартная (sдля всех, lкроме жавистов). Если функция подстроки — substr(строка превышает заданную длину, она обрезается предпочтительно по пробелу начало, длина), или Tab’уsubstr(строка, а в конец добавляется «…» начало). Причём начало и длина могут быть отрицательными, тогда они считаются относительно длины строки. ==== TRIM ==== Удаление пробелов из начала и конца строки. ==== SPLIT ==== Разделение строки по регулярному выражению и лимиту — split(троеточиеRegExp, аргумент, лимит).Лимит необязателен. (см. [http://perldoc.perl.org/functions/split.html perldoc -f split])
==== S=HTML=HTMLSPECIALCHARS, T=STRIP, H=STRIP_UNSAFE, NL2BR ====
Преобразование символов < > & " ' в HTML-сущности.
Удаление всех [[lib:HTML|HTML]]/[[lib:XML|XML]] тегов.
Удаление только запрещённых «небезопасных» HTML-тегов.
Преобразование переводов строк (\n) в HTML-тег <tt><nowiki><br /></nowiki></tt>.
=== URI_QUOTE=URIQUOTE=URLENCODE === URL-кодирование строки ({{CPAN|URI::Escape}} в Perl и [http://php.net/manual/en/function.urlencode.php urlencode()] в PHP). === CONCAT, JOIN=IMPLODE ====
Конкатенация всех своих аргументов — concat(аргументы). Конкатенирует также все элементы всех переданных массивов.
Конкатенация элементов массива через разделитель — join(строка, аргументы). Конкатенирует также все элементы всех переданных массивов.
=== SUBSTR=SUBSTRINGSUBST, STRLEN SPRINTF, STRFTIME ====
Стандартная (для всех кроме жавистов стандартная) функция подстроки — substrПодстановка на места подстрок вида $ЧИСЛО соответствующих параметров функции или элементов переданного массива — subst(строка, начало$1, длина)$2, или substr(строка, начало). Причём начало и длина могут быть отрицательными, тогда они считаются относительно длины строки.
Ну Sprintf — он и функция «длина строки»в Африке [http://perldoc.perl.org/functions/sprintf.html sprintf].
=== Q=QUOTE=ADDSLASHESФорматирование даты и/или времени с помощью функции [http://www.manpagez.com/man/3/strftime/ strftime] — strftime(формат, REQUOTE=RE_QUOTE=PREG_QUOTE ===дата [, часть_даты]). Формат strftime’овский (например, «%d %b %Y»). Дата может передаваться как один или два аргумента, если два — они конкатенируются через пробел. Далее дата разбирается способом, похожим на wfTimestamp() в MediaWiki. Принимается следующее:* UNIX время.* Времена типа MySQL DATE, MySQL DATETIME, EXIF, ISO 8601, MediaWiki, и любые другие, подпадающие под следующий формат: 1 группа из 4 или более цифр (год) и 2 (месяц, день) или 5 (месяц, день, часы, минуты, секунды) групп по 2 цифры, разделённые любыми нецифровыми символами и в конце — опционально временная зона — 2 цифры, предварённые пробелом, плюсом или минусом. Короче говоря, <pre>^\D*(\d{4,})\D*(\d{2})\D*(\d{2})\D*(?:(\d{2})\D*(\d{2})\D*(\d{2})\D*([\+\- ]\d{2}\D*)?)?$</pre>* Оракловский формат даты-времени: <nowiki>ДД-Мес-ГГ[ГГ] ЧЧ.ММ.СС</nowiki>.* RFC 822.
Экранирование символов " ' \ и перевода строки бэкслэшем — quote(строка).==== STRLIMIT ====
Экранирование символовОграничение длины строки s максимальной длиной l — strlimit(s, являющихся специальными в регулярных выражениях — re_quote(строкаl). Если строка превышает заданную длину, она обрезается предпочтительно по пробелу или Tab’у, а в конец добавляется «…» (см. [http://perldoc.perl.org/perlre.html perldoc perlre]троеточие).
=== REPLACE, SPLIT Массивы и хеши ===
Замена Perl- (соответственно PCRE- в PHP-версии) регулярного выражения в строке — replace(RegExp, замена, строка).==== HASH ====
Разделение строки по регулярному выражению и лимиту — split(RegExp, аргумент, лимит)Создание хэша из всех аргументов. Лимит необязателен. (см. [http://perldoc.perl.org/functions/split.html perldoc -f split])
Соответственно в хеше аргументы идут парами КЛЮЧ, ЗНАЧЕНИЕ, КЛЮЧ, ЗНАЧЕНИЕ и т. п. (специального синтаксиса «=>» нет). == DUMP== KEYS, JSON HASH_KEYS, ARRAY_KEYS ==== Массив ключей хэша. Понятное дело, в PHP их порядок сохраняется, а в Perl — нет. ==== SORT ==== Сортировка массива по значениям. ==== EACH ==== Массив хэшей вида <tt>{ id => ключ, name => значение }</tt> для хэша, в случае Perl ключи будут отсортированы по имени. ==== ARRAY, RANGE ==== Создание массива. Диапазон от A до B — range(A, B). ==== IS_ARRAY ==== Проверка, является ли аргумент массивом. В PHP-версии не проверяется, а не является ли он при этом хэшем, ибо трудоёмко. ==== COUNT, SUBARRAY=ARRAY_SLICE, SUBARRAY_DIVMOD ==== Количество элементов массива, или 0, если аргумент — не массив — count(аргумент). Аналог функции [http://php.net/manual/en/function.array-slice.php array_slice] из PHP. Выбор из массива каждого div’того элемента, начиная с номера mod или нуля по умолчанию — subarray_divmod(массив, div, mod). ==== GET, AGET, HGET ==== Получение элемента массива/хэша по «динамическому» ключу. По-моему, это лучше, чем зюки-хрюки Template Toolkit’а: <tt>hash.${hash2.$key}</tt> и т. п. <tt>GET(откуда, что)</tt> автоматически решает, «откуда» — это массив или хеш, AGET служит только для массивов, а HGET только для хешей. В PHP-версии все три идентичны. <tt>GET(что)</tt> — получение значения переменной верхнего уровня. ==== ARRAY_MERGE ==== Слить массивы в один. Под Perl — только массивы (не хеши), под PHP — любые массивы. ==== SHIFT, POP, UNSHIFT, PUSH ==== Вынуть элемент из начала массива, вынуть из конца, добавить в начало — <tt>unshift(array, value)</tt>, добавить в конец — <tt>push(array, value)</tt>. ==== VOID ==== Вычислить аргумент и вернуть пустую строку. Потенциально нужно для игнорирования результата, ибо все возвращаемые значения радостно подставляются в выходной поток. ==== DUMP=VAR_DUMP ====
Вывод всех данных из структуры — Dumper в Perl’е и var_dump в PHP.
Форматирование структуры данных в формат ==== JSON.====
Форматирование любой структуры данных в формат JSON. ==== INCLUDE=PROCESS=PARSE ====
Включение другого шаблона или выполнение блока.
</pre>
=== SUBST, SPRINTF, STRFTIME = CALL ====
Подстановка на места подстрок вида $ЧИСЛО соответствующих параметров функции или элементов переданного массива — substВызов метода объекта по «динамическому» имени — <tt>call(строкаvarref, $1method_name, $2arg1, arg2, arg3, ...)</tt>.
Sprintf — он и в Африке [http://perldoc.perl.org/functions/sprintf.html sprintf].==== MAP ====
Форматирование даты и/или времени с помощью Применение функции [http://www.manpagez.com/man/3/strftime/ strftime] — strftime(формат, дата [, часть_даты]). Формат strftime’овский (например, «%d %b %Y»). Дата может передаваться имя которой передано как один или два аргумента, если два — они конкатенируются через пробел. Далее дата разбирается способом, похожим на wfTimestamp() в MediaWiki. Принимается следующее:* UNIX время.* Времена типа MySQL DATE, MySQL DATETIME, EXIF, ISO 8601, MediaWikiпервый аргумент, ко всем переданным аргументам и любые другие, подпадающие под следующий формат: 1 группа из 4 или более цифр элементам всех переданных массивов — map(год) и 2 (месяц«имя_функции», день) или 5 (месяц, день, часы, минуты, секунды) групп по 2 цифры, разделённые любыми нецифровыми символами и в конце — опционально временная зона — 2 цифры, предварённые пробелом, плюсом или минусом. Короче говоря, <pre>^\D*(\d{4,})\D*(\d{2})\D*(\d{2})\D*(?:(\d{2})\D*(\d{2})\D*(\d{2})\D*([\+\- ]\d{2}\D*)?аргументы)?$</pre>* Оракловский формат даты-времени: <nowiki>ДД-Мес-ГГ[ГГ] ЧЧ.ММ.СС</nowiki>.* RFC 822.
[[Категория:Sway]]
[[Категория:Разработка]]
[[Категория:Perl]]