Содержание
Список таблиц
Список примеров
Blitz родился весьма неоригинально, for fun. Однако, поигравшись с ним немного, мне показалось, что скорость, с которой он работает, и удобства, которые он предоставляет разработчику — стоят того, чтобы дать его поиграться коллегам. Основных «фишек» у Blitz три:
написан как PHP-модуль на Си, и является одним из самых быстрых движков;
имеет простой и интуитивно понятный синтаксис;
позволяет структурировать код удобным и легко читаемым образом.
Blitz поддерживает разделение и скрытие функционально различных частей шаблонов с помощью простого механизма: текст шаблона может содержать вызов методов объекта, который этим шаблоном управляет. Таким образом, достигается основная цель: шаблон не содержит большого количества блоков и контекстов, часто мешающих разобраться, что к чему. Напротив, даже в проекте со сложной логикой представления при правильном подходе шаблоны будут давать разработчику своеобразную «карту» всего проекта. Blitz также позволяет включать одни шаблоны в другие (аналог include
) и поддерживает условный вывод переменных (аналог if
).
Начиная с версии 0.4 в Blitz добавлен функционал движка php_templates. Теперь в Blitz можно создавать множество вложенных шаблонов внутри одного файла, это сильно упрощает жизнь для очень сложных шаблонов с одной стороны и улучшает показатели по производительности для ряда задач с другой.
Также с версии 0.4 есть экспериментальная поддержка работы с набором «упакованных» шаблонов (blitzpack), когда несколько шаблонов сначала единожды «компилируются» в бинарный формат, упаковываются в один файл, и затем работа ведется только с этой «бинарной пачкой» шаблонов, экономя время на файловых операциях и разборе шаблонов.
Мне бы не хотелось здесь следовать академической традиции и проводить подробный анализ других проектов. В любом случае, если вы научились эффективно использовать сам PHP в качестве шаблонного движка, обходясь без сторонних продуктов и библиотек — вы счастливый человек. Вы используете самый эффективный с точки зрения производительности подход, и если он вам удобен — придерживайтесь его. Если нет — попробуйте Blitz. Возможно, он вас приятно удивит ;)
Статус проекта — полуэкспериментальный, но я считаю текущую версию вполне работоспособной. В силу параноидального отношения к качеству проекта, 100%-я стабильность и обратная совместимость до версии 1.0 не гарантируется.
К сожалению, мне неизвестна ни одна простая, универсальная и по-настоящему корректная методика анализа производительности шаблонных движков. А результатами любых искусственных, или как их ещё принято называть, синтетических, тестов пользоваться нужно максимально осторожно. Тем не менее, здесь приводятся результаты двух тестов. Первый тест — классический, измеряющий скорость выполнения циклических итераций одного и того же шаблона. Тест крайне простой, но позволяющий достаточно условно разделить группы движков на «нормальные», «медленные» и «никуда не годные». Число итераций и переменных в блоке было взято по умолчанию (9 переменных, 50 итераций), результаты этого теста приведены в таблице 1. Как легко видеть, Blitz, по крайней мере, аутсайдером не является.
Таблица 2.1. Классический тест производительности
Тестовая машина (A): XEON*2 2,4GHz (HT on) 2GB; linux php-4.3.10(fcgi) zps nginx blitz, php_templates: so-модули, CFLAGS: -g3 -O2 | |||
---|---|---|---|
№ | Engine name | Time | Percentage |
1 | php | 0.000544 | 100% |
2 | blitz | 0.001008 | 185% |
3 | php_templates | 0.001812 | 333% |
4 | smarty | 0.002006 | 369% |
5 | str_replace | 0.003713 | 683% |
6 | phemplate | 0.004514 | 830% |
7 | fasttemplate | 0.006835 | 1256% |
8 | vtemplate | 0.009565 | 1758% |
9 | ultratemplate | 0.012993 | 2388% |
10 | templatepower | 0.017056 | 3135% |
11 | bugitemplate | 0.019989 | 3674% |
12 | phplib | 0.028053 | 5157% |
13 | profTemplate | 0.043104 | 7924% |
14 | xtemplate | 0.048799 | 8970% |
Тестовая машина (B): PC PIV 2,8GHz (HT off) 1GB; linux-2.6.8 php-4.3.10 (Apache/1.3.33 static) zps blitz, php_templates: so-модули, CFLAGS -g -O2 | |||
---|---|---|---|
№ | Engine name | Time | Percentage |
1 | php | 0.00045 | 100% |
2 | blitz | 0.000834 | 185% |
3 | php_templates | 0.001595 | 354% |
4 | smarty | 0.001694 | 376% |
5 | str_replace | 0.00373 | 829% |
6 | phemplate | 0.004215 | 937% |
7 | fasttemplate | 0.006139 | 1364% |
8 | vtemplate | 0.008755 | 1946% |
9 | ultratemplate | 0.012747 | 2833% |
10 | templatepower | 0.018678 | 4151% |
11 | bugitemplate | 0.019286 | 4286% |
12 | phplib | 0.025478 | 5662% |
13 | profTemplate | 0.045148 | 10033% |
14 | xtemplate | 0.048137 | 10697% |
Столь сильное отличие php от прочих движков объясняется тем, что весь код php-теста упакован в один файл, в то время для остальных есть два файла — php-файл контроллера и шаблонный файл, который парсится котроллером.
В результаты этого теста не включены некоторые известные шаблонные движки, такие как madtemplate, PEAR::Sigma и PEAR::HTML_Template_IT по простой причине: они не были установлены на тестовых машинах. Однако, насколько мне известно, эти проекты не являются кандидатами на попадание в пятерку лидеров. В этом можно убедиться, например, проведя онлайн-тесты самостоятельно, или скачав тестирующую программу.
Второй тест более приближен к полевым условиям. Он представляет собой тестирование некоторой динамической страницы, подготовленной с использованием разных движков, при помощи стандартной утилиты ab. Итак, у нас есть страница какого-то псевдопортала, содержащая:
ротирующиеся рекламные уши (3 шт.);
«полосатую» навигацию (~10 разделов);
горячие новости (~10 шт.);
список пользователи онлайн (~20 шт.);
голосовалка с вариантами ответов (3 ответа);
прочие переменные на странице (~5 шт).
Для тестирования было выбрано 4 подхода:
ugly php mess: используется только php, причем весь код полностью упакован в один файл, представляя собой эдакую «кашу». Такой прием практически никогда не встречается в реальных больших проектах, но включен в тесты исключительно ради интереса, поскольку очевидно является самым быстрым.
php includes: используется только php, функционально разные блоки (элементы списков) вынесены в отдельные файлы.
php_templates: один шаблон, на каждый функциональный блок — контекст.
blitz includes: разные шаблоны на каждый функциональный блок, подключаемые через include
.
blitz ctx: один шаблон, на каждый функциональный блок — контекст.
blitz ctx arrays: один шаблон, на каждый функциональный блок — контекст, один вызов установки массива итераций.
blitzpack: разные шаблоны на каждый функциональный блок, упакованые в один blitzpack, подключаемые через include
.
smarty: один шаблон, на функциональные блоки — циклы внутри шаблона.
Все данные упакованы в структуру в отдельном файле, который инклюдится во всех тестовых вариантах. Числа запросов в секунду, которое выполняет сервер для каждого из методов, представлены в таблице 2.
Таблица 2.2. Тест производительности приближенный к полевым условиям
Тестовая машина(B), см. таблицу 1 | |
---|---|
ab -n20000 -c100, ZPS on | |
ugly php mess | 1150 |
blitz ctx arrays | 890 |
blitz ctx | 825 |
php includes | 770 |
blitzpack | 725 |
blitz incudes | 680 |
smarty | 620 |
php_templates | 615 |
Тестовая машина(B), см. таблицу 1 | |
---|---|
ab -n20000 -c100, ZPS off | |
ugly php mess | 660 |
blitz ctx arrays | 590 |
blitz ctx | 560 |
php_templates | 450 |
blitzpack | 440 |
blitz incudes | 430 |
php includes | 285 |
smarty | 125 |
К сожалению, я не имел возможности провести тесты для других шаблонных движков (впрочем, код для этого теста доступен, вы можете добавить в него решения исходной задачи с использованием любых других средств). Поэтому ограничусь обобщенной интерпретацией этих результатов. То, что native PHP-код вместе с акселератором всегда будут быстрее прочих решений — очевидно. Правда, следует особенно подчеркнуть, что native в этом смысле — именно написанный программистом самим, а не «скомпилированный». В этом легко убедиться, заглянув внутрь любого «скомпилированного» шаблона: как правило, их код состоит из многомерных, довольно сложных для выполнения конструкций, значительно сложнее, чем написанный правильными руками код ;) Поскольку разница между Blitz и «правильным» методом php includes не является кардинальной, а все синтетические тесты позволяют лишь выявить группы приблизительно равных, можно с определенной долей уверенности считать методы разработки с использованием PHP, Blitz и php_templates примерно одинаковыми по производительности.
Следует также принять во внимание, что в реальном проекте разница в скорости между различными методами, скорее всего, будет ещё меньше. Во-первых, это связано с тем, что значительное время будет тратиться на работу с источниками данных (СУБД, различные сервисы и проч.). Во-вторых, отношение «количества» кода, относящегося к уровню представления, и прочего кода будет совершенно иным. Грубо говоря, view_code = full_code для тестов и пусть выигрыш на синтетическом тесте составляет даже десятки процентов. Но в реальном проекте часто выполняется соотношение view_code >> full_code, и поэтому выигрыш на уровне представления уже почти ничего не даст. Как вы могли заметить, почти все тесты были проведены с использованием акселератора из ZPS. Вряд ли сейчас можно представить крупный проект, в котором не используется акселератор, однако, акселератор акселератору рознь. И вполне возможно вы получите совершенно иные результаты при использовании, например, eAccelerator'a. В-общем, призываю вас не полагаться полностью на приведенные результаты. Скачивайте тесты, экспериментируйте на реальных задачах, и выбирайте те решения, которые дают выигрыш в вашем проекте.
Содержание
Blitz — расширение PHP, поставляемое пока исключительно в исходных кодах, поэтому его установка состоит из обычных шагов по сборке расширения:
tar zxvf blitz.tar.gz
cd blitz
phpize
./configure
make
make install
Вы можете протестировать Blitz запустив скрипт run-tests.sh
.
run-tests
(поставляется вместе с PHP).
bash>./run-tests.sh ===================================================================== CWD : /home/fisher/prj/blitz/tests PHP : /usr/local/bin/php PHP_SAPI : cli PHP_VERSION : 4.3.10 ZEND_VERSION: 1.3.0 PHP_OS : Linux - Linux fisher 2.6.8-24.19-smp #1 SMP Tue Nov 29 14:32:45 UTC 2005 i686 INI actual : /usr/local/lib/php.ini More .INIs : Extra dirs : ===================================================================== Running selected tests. PASS contexts [context.phpt] PASS errors and warnings [errors.phpt] PASS fetch [fetch.phpt] PASS complex fetch [fetch_cmplx.phpt] PASS predefined methods: if [if.phpt] PASS predefined methods: include [include.phpt] PASS user-defined methods [method.phpt] PASS method call from inner include [mfi.phpt] PASS variables [var.phpt]
После этого вы, возможно, захотите отредактировать свой php.ini, включив blitz в список расширений:
extension=blitz.so
Сборка blitz тестировалась на Linux 2.6 (i386) и Windows XP. Пользователи Windows могут воспользоваться готовыми Win32-бинарниками.
Таблица 4.1. Параметры конфигурации
Имя | Описание | Значение по умолчанию | Изменяемость |
---|---|---|---|
blitz.tag_open | открывающий тег | {{ | PHP_INI_ALL |
blitz.tag_close | закрывающий тег | }} | PHP_INI_ALL |
blitz.var_prefix | префикс переменной | $ | PHP_INI_ALL |
$test
, вы должны вставить следующий код в ваш шаблон: {{ $test }}
Как и во многих других шаблонных движках двумя базовыми сущностями проекта, которые использует Blitz, являются собственно шаблон и объект, управляющий выполнением этого шаблона (контроллер шаблона).
Класс Blitz
— внутренний класс расширения, управляющий шаблоном. Первый и единственный параметр конструктора класса — имя шаблона. Этот параметр необязателен — можно загрузить шаблон из переменной PHP используя метод load()
.
Blitz не поддерживает по принципиальным соображениям сложные выражения:
{{if(if($foo, 0, 1), 'bar', 'foobar')}}
Данный код работать не будет. Не надо превращать код в спагетти.
Начиная с версии 0.4 в Blitz практически без изменений была добавлена функциональность движка php_templates. Суть контекстов заключается в следующем. Обычно мы имеем дело с «плоскими» шаблонами, в них есть либо переменные, либо какие-то операторы или вызовы, которые обязательно исполняются. Контексты — это подшаблоны, которые не используются до тех пор, пока контроллер шаблона явно это не укажет. Например, если у нас есть php-код
переменная: <?=$a?>, метод: <?=b()?>
, то оба куска этого кода будут всегда исполнены. Никакой иерархии нет, все php-шаблоны плоские. Теперь рассмотрим некий псевдокод с контекстами
переменная : {{ $a }}, контекст {{ BEGIN b }} что-то внутри {{ END }}
Здесь b — это контекст, который по умолчанию не будет использован (чаще используют термин «итерирован») - и вместо кода от BEGIN
до END
ничего не будет. Если контекст итерирован один раз, то в шаблоне появится результат исполнения внутренней части контекста. Если проитерировать дважды — результат исполнения внутренней части контекста два раза. Параметры у каждой итерации, разумеется, могут быть разными. Таким образом, для отображения списков достаточно просто итерировать контекст, описывающий элемент списка, для каждого элемента.
Самое удобное заключается в том, что контексты могут быть вложены друг в друга. Каждый контекст однозначно определён своим путем — /root/node/item
означает, что есть контекст root, внутри которого контекст node внутри которого item. Если итерировать родительский контекст с одними параметрами, потом вложенные контексты, потом снова родительские контексты с другими параметрами, а потом снова вложенные, то можно при помощи одного единственного шаблона сделать страницу абсолютно любой сложности.
Есть базовые операции с контекстами — установить текущий контекст и итерировать контекст. Установка означает, что все вызовы по умолчанию работают с этим контекстом, тут есть хорошая аналогия с работой в командной оболочке — установить текущий контекст в /root/node/item
по смыслу то же самое что сделать cd в /root/node/item
. А итерировать фактически означает «исполнить».
Имя контекста чувствительно к регистру.
Передавая параметр context_path в любую из функций, вы можете передавать его в двух формах:
абсолютной
/context1/context2/context3
относительной
context2/context3
../context3
В Blitz внутри контекстов также доступны такие приятные мелочи как if()
, include()
и вызов пользовательского метода.
Следующий код выводит ужасно доставшее всех знакомое всем приветствие, запрятанное в трех вложенных контекстах.
Пример 6.1. Ужасно доставшее всех знакомое всем приветствие, запрятанное в трех вложенных контекстах
{{ BEGIN root }} {{ BEGIN node }} {{ BEGIN item }} hello, world {{ END }} {{ END }} {{ END }}
<? $T = new Blitz('tpl'); $T->iterate('/root/node/item'); echo $T->parse(); ?>
hello, world
Пример 6.2. Работа с простыми списками
{{ BEGIN row }}row #{{ $i }} {{ END }}
<? $T = new Blitz('tpl'); $max_num_list = 5; // use context & iterate $T->context('row'); for($i=0; $i<$max_num_list; $i++) { $T->iterate(); $T->set(array('i' => $i)); } // or just use block for($i=0; $i<$max_num_list; $i++) { $T->block('/row',array('i' => $i)); } echo $T->parse(); ?>
row #0 row #1 row #2 row #3 row #4 row #0 row #1 row #2 row #3 row #4
Метод block()
— удобная замена последовательным iterate()
и set()
, которые встречаются в коде очень часто именно вместе. Разумеется, в Blitz внутри контекста можно использовать и include()
, и if()
, и пользовательские методы. Переменные, установленные в родительских контекстах, «не видны» в дочерних. Если есть необходимость в глобальных переменных, которые будут «видны» в любом месте шаблона — можно использовать метод setGlobal()
вместо set()
.
Пример 6.3. Как при помощи вложенных контекстов строить более сложные списки
complex list example {{ BEGIN list; }} list #{{ $list_num }} {{ BEGIN list_empty; }} this list is empty {{ END }}{{ BEGIN list_item; }} row #{{ $i_row; }} {{ END }} {{ END }}
<? $T = new Blitz('tpl'); $max_num_list = 5; $max_num_item = 5; $T->context('/list'); for($i=0; $i<$max_num_list; $i++) { $T->block('',array('list_num' => $i)); $is_empty = $i%2; // emulate empty sub-lists if($is_empty) { $T->block('list_empty'); } else { for($j=0; $j<$max_num_item; $j++) { $T->block('list_item',array('i_row' => $i.':'.$j)); } } } echo $T->parse(); ?>
complex list example list #0 row #0:0 row #0:1 row #0:2 row #0:3 row #0:4 list #1 this list is empty list #2 row #2:0 row #2:1 row #2:2 row #2:3 row #2:4 list #3 this list is empty list #4 row #4:0 row #4:1 row #4:2 row #4:3 row #4:4
Фактически на этом простом механизме попеременных итераций вложенных контекстов реализуется абсолютно любая логика даже в одном единственном шаблоне.
В-общем, функционал контекстов достаточно мощный для того, что бы использовать шаблонный движок для сколь угодно сложных проектов.
Blitz поддерживает 4 типа:
Типы аналогичны типам PHP, за исключением того, что нет разницы — заключена строка в двойные или одинарные кавычки.
Возможность включать в шаблон пользовательские методы - самая интересная с точки зрения организации хорошего и удобно читаемого кода. До сих пор в примерах использовался стандартный класс Blitz
, никакими новыми методами не обладающий. Однако если создать объект класса-наследника Blitz
, который предоставляет некоторый метод my_test
, в шаблоне можно использовать вызов этого метода ровно с таким же названием.
Пример 8.1. Вызов пользовательского метода
пример вызова пользовательского метода: {{ my_test }}
<? class BlitzTemplate extends Blitz { function my_test() { return 'user method called ('.__CLASS__.','.__LINE__.')'; } } $T = new BlitzTemplate('tpl'); echo $T->parse(); ?>
пример вызова пользовательского метода: user method called (blitztemplate,5)
Все, что возвращает пользовательский метод, будет конвертировано в строку и подставлено вместо вызова. Если вызов метода в шаблоне есть, но самого метода нет — будет подставлена пустая строка. Вообще, действует обычное правило: никаких исходных вызовов никогда не присутствует в конечном результате, независимо от существования переменной, метода и проч.
Внутри пользовательского метода также можно включать другие шаблоны. Конечно, никто не запрещает вам написать что-нибудь вроде:
class BlitzTemplate extends Blitz { var $data; var $TItem; function BlitzTemplate($t,$titem) { parent::Blitz($t); $TItem = new Blitz($titem); } function set_data() { // some code } function my_test() { $result = ''; foreach ($this->data as $i_data) { $result .= $TItem->parse($i_data); } return $result; } } $T = new BlitzTemplate('main.tpl','item.tpl'); // $bla_bla = ... $T->set_data($blabla); echo $T->parse();
Этот метод будет работать, но не очень хорош по двум причинам. Во-первых, $TItem
является совершенно отдельным объектом, никак не связанным с $T
. Blitzу несколько сложнее переключаться с одного объекта на другой, нежели выполнять все операции через один и тот же объект. Во-вторых, $TItem
не будет наследовать установленные переменные из $T
, их при необходимости нужно будет протягивать самостоятельно, а также внутри $TItem
нельзя использовать методы $T
. Поэтому более правильным будет использование встроенного метода include()
.
Начиная с версии 0.3 в Blitz поддерживается передача параметров из шаблона в пользовательский метод.
Пример 8.2. Передача параметров из шаблона в пользовательский метод
calling template with arguments: {{ my_test(134,$x,"hello,world!",$dummy) }}
<? class BlitzTemplate extends Blitz { var $titem; function BlitzTemplate($t) { parent::Blitz($t); $this->set(array('x' => 1234)); } function my_test($p1,$p2,$p3,$p4) { $result = 'user method called ('.__CLASS__.','.__LINE__.')'."\n"; $result .= 'parameters are:'."\n"; $result .= '1:'.var_export($p1,TRUE)."\n"; $result .= '2:'.var_export($p2,TRUE)."\n"; $result .= '3:'.var_export($p3,TRUE)."\n"; $result .= '4:'.var_export($p4,TRUE)."\n"; return $result; } } $T = new BlitzTemplate('tpl'); echo $T->parse(); ?>
calling template with arguments: user method called (blitztemplate,12) parameters are: 1:134 2:1234 3:'hello,world!' 4:NULL
Переменные представлены знаком blitz.var_prefix с последующим именем переменной. Имя переменной чувствительно к регистру.
Пример 9.1. Переменные
Это некоторый тест для двух переменных: {{ $a }} и {{ $b }}, номер итерации: {{ $i }}
<? $T = new Blitz('tpl'); $i = 0; $i_max = 10; for ($i = 0; $i<$i_max; $i++) { echo $T->parse( array( 'a' => 'var_'.(2*$i), 'b' => 'var_'.(2*$i+1), 'i' => $i ) ); } ?>
Это некоторый тест для двух переменных: var_0 и var_1, номер итерации: 0 Это некоторый тест для двух переменных: var_2 и var_3, номер итерации: 1 Это некоторый тест для двух переменных: var_4 и var_5, номер итерации: 2 Это некоторый тест для двух переменных: var_6 и var_7, номер итерации: 3 Это некоторый тест для двух переменных: var_8 и var_9, номер итерации: 4 Это некоторый тест для двух переменных: var_10 и var_11, номер итерации: 5 Это некоторый тест для двух переменных: var_12 и var_13, номер итерации: 6 Это некоторый тест для двух переменных: var_14 и var_15, номер итерации: 7 Это некоторый тест для двух переменных: var_16 и var_17, номер итерации: 8 Это некоторый тест для двух переменных: var_18 и var_19, номер итерации: 9
Содержание
Содержание
(blitz ≥ 0.4.10)
clean — очистить переменные и итерации контекста$Tpl->clean($context_path)
очищает переменные и итерации контекста. Параметр $context_path
по умолчанию равен корню (/
) — $Tpl->clean()
без параметров очистит все переменные и итерации шаблона.
Второй параметр управляет генерацией предупреждения PHP когда очищаемая итерация не найдена, по умолчанию true
.
Пример 8. clean
================================ context cleaning ({{ $var }}) ================================ <!-- BEGIN a -->context (a) {{ $va }} <!-- BEGIN b -->context (b) {{ $vb }} <!-- END b --> <!-- END -->
<?php $T = new Blitz('tpl'); $T->set(array('var' => 'Hello, World!')); $T->block('/a', array('va' => 'va_value')); $T->block('/a/b', array('vb' => 'vb_value')); echo $T->parse(); $T->clean('/a/b'); echo $T->parse(); $T->clean('/a'); echo $T->parse(); $T->block('/a', array('va' => 'va_value_new')); $T->iterate('/a/b'); echo $T->parse(); $T->clean(); echo $T->parse(); ?>
================================ context cleaning (Hello, World!) ================================ context (a) va_value context (b) vb_value ================================ context cleaning (Hello, World!) ================================ context (a) va_value ================================ context cleaning (Hello, World!) ================================ ================================ context cleaning (Hello, World!) ================================ context (a) va_value_new context (b) ================================ context cleaning () ================================
(blitz ≥ 0.4)
context — установить контекстПример 9. context
{{BEGIN user}} {{BEGIN hello}} Hello, user! {{END}} {{BEGIN goodbye}} Goodbye, user! {{END}} {{END}} {{BEGIN world}} Hello, world! {{END}}
<?php $Template = new Blitz('tpl'); $Template->context('user'); $Template->block('hello'); $Template->block('goodbye'); $Template->block('../world'); echo $Template->parse(); ?>
Hello, user! Goodbye, user! Hello, world!
См. также block()
.
(blitz ≥ 0.4)
dumpIterations — дамп итерацийПсевдоним метода — dump_iterations
.
Пример 10. dumpIterations
{{BEGIN counter}} {{$i}}, {{END}}
<?php $Template = new Blitz('tpl'); for ($i = 0; $i < 3; $i++) { $Template->block('counter', array('i' => $i)); } $Template->dumpIterations(); ?>
ITERATION DUMP (4 parts) (1) iterations: array(1) { [0]=> array(1) { ["counter"]=> array(3) { [0]=> array(1) { ["i"]=> int(0) } [1]=> array(1) { ["i"]=> int(1) } [2]=> array(1) { ["i"]=> int(2) } } } } (2) current path is: / (3) current node data (current_iteration_parent) is: array(1) { [0]=> array(1) { ["counter"]=> array(3) { [0]=> array(1) { ["i"]=> int(0) } [1]=> array(1) { ["i"]=> int(1) } [2]=> array(1) { ["i"]=> int(2) } } } } (4) current node item data (current_iteration) is: array(1) { ["counter"]=> array(3) { [0]=> array(1) { ["i"]=> int(0) } [1]=> array(1) { ["i"]=> int(1) } [2]=> array(1) { ["i"]=> int(2) } } }
См. также dumpStruct()
.
(blitz ≥ 0.4)
dumpStruct — дамп структурыПсевдоним метода — dump_struct
.
Пример 11. dumpStruct
{{BEGIN counter}} {{$i}}, {{END}}
<?php $Template = new Blitz('tpl'); for ($i = 0; $i < 3; $i++) { $Template->block('context', array('i' => $i)); } $Template->dumpStruct(); ?>
== TREE STRUCT (2 nodes): ^-begin[22] (0(17), 32(27)); ARGS(1): counter(0); CHILDREN(1): ^-i[1] (19(0), 23(0)); == PLAIN STRUCT (2 nodes): begin[22] (0(17), 32(27)); ARGS(1): counter(0); CHILDREN(1): i[1] (19(0), 23(0));
См. также dumpIterations()
.
(blitz ≥ 0.4)
fetch — использовать контент одного шаблона при работе с другим шаблоном или тело одного контекста в одном шаблоне внутри другогоПример 12. fetch
{{ BEGIN online }} online! {{ END }} {{ BEGIN offline }} was online {{ $n }} {{ BEGIN h }}hours{{ END }}{{ BEGIN d }}days{{ END }}{{ BEGIN m }}months{{ END }} ago {{ END }} {{ BEGIN away }} away... {{ END }}
<? $T = new Blitz('tpl'); // online echo $T->fetch('online')."\n"; // away echo $T->fetch('away')."\n"; $T->context('offline'); // 15 days ago $T->iterate('d'); echo $T->fetch('offline', array('n' => 15))."\n"; // 2 months ago $T->iterate('m'); echo $T->fetch('offline', array('n' => 2))."\n"; ?>
online! away... was online 15 days ago was online 2 months ago
Метод fetch получает результат исполнения последней итерации контекста.
iterate()
, чтобы очистить извлеченные итерации. С версии 0.4.2 каждый вызов fetch
автоматически очищает предыдущие итерации контекста.
(blitz ≥ 0.1)
include — подключение другого шаблонаПример 14. include
<?php class View extends Blitz { var $news = array(); function View($tmpl_name) { return parent::Blitz($tmpl_name); } function set_news($data) { $this->news = $data; } function list_news() { $result = ''; foreach($this->news as $i_news) { $result .= $this->include('news_list_item.tpl', $i_news); } return $result; } } ?>
Метод list_news
возвращает результат исполнения шаблона news_list_item.tpl
, передавая данные новости как глобальные переменные в подключаемый шаблон. В текущей версии (0.4.3) include
не поддерживает итерацию контекстов — все контексты подключаемого шаблона будут скрыты. Нет возможности передать составные итеративные данные — только одномерный ассоциативный массив глобальных переменных. Если необходимо подключить сложные шаблоны с вложенными контекстами, используйте fetch()
.
(blitz ≥ 0.4)
iterate — итерировать контекстПример 15. iterate
{{BEGIN hello}} Hello, user! {{END}} {{BEGIN goodbye}} Goodbye, user! {{END}}
<?php $Template = new Blitz('tpl'); $Template->iterate('hello'); $Template->context('goodbye'); $Template->iterate(); echo $Template->parse(); ?>
Hello, user! Goodbye, user!
(blitz ≥ 0.1)
parse — разобрать шаблонПример 17. parse без установки глобальных переменных
Hello, world!
<?php $Template = new Blitz('tpl'); echo $Template->parse(); ?>
Hello, world!
Пример 18. parse с установкой глобальных переменных
Hello, {{$object}}!
<?php $Template = new Blitz('tpl'); echo $Template->parse(array('object' => 'world')); ?>
Hello, world!
(blitz ≥ 0.1)
set — установить переменныеПример 19. set
Hello, {{$object}}!
<?php $Template = new Blitz('tpl'); $Template->set(array('object' => 'world')); echo $Template->parse(); ?>
Hello, world!
Пример 20. set как «быстрый» способ установить целый массив итераций
<projects> {{BEGIN project}} <project label="{{$url}}" data="{{$id}}"/> {{END}} </projects>
<?php $data = array ( 'project' => array( 0 => array('url' => 'a', 'id' => '1'), 1 => array('url' => 'b', 'id' => '2'), 2 => array('url' => 'c', 'id' => '3'), ) ); $Template = new Blitz('tpl'); $Template->set($data); echo $Template->parse(); ?>
<projects> <project label="a" data="1"/> <project label="b" data="2"/> <project label="c" data="3"/> </projects>
Массив $data
описывает 3 итерации контекста project
с их локальными переменными url
и id
. Структура данных может быть сколь угодно сложной, но при соблюдении следующего правила: числовые ключи для итераций контекста, строчные для имен контекстов и переменных. Таким образом можно не вызывать context/iterate/set, а сначала «приготовить» такую вот структуру данных, а потом одним махом засадить эти итерации в шаблон — иногда это удобно (к примеру, вместе с PDO::fetchAll(PDO::FETCH_ASSOC)
) и вообще говоря, это работает очень быстро (blitz ctx arrays в benchmarks).
См. также setGlobal()
, block()
.
(blitz ≥ 0.4)
setGlobal — установить глобальные переменныеПсевдоним метода — set_global
.
Пример 21. setGlobal
I am {{$local}} variable. I am {{$global}} variable. {{BEGIN context}} I am {{$local}} variable. I am {{$global}} variable. {{END}}
<?php $Template = new Blitz('tpl'); $Template->set(array('local' => 'local (root)')); $Template->setGlobal(array('global' => 'global')); $Template->block('context', array('local' => 'local (context)')); echo $Template->parse(); ?>
I am local (root) variable. I am global variable. I am local (context) variable. I am global variable.
См. также set()
.
Содержание
(blitz ≥ 0.4.11)
date — форматировать дату/времяformat
задается так же как и для функции PHP strftime
.
Если time
— число, то трактуется как метка времени UNIX, иначе как GNU формат даты.
Пример 22. date
{{ date("%d %m %Y %H:%M:%S", $time_num) }} {{ date("%d %m %Y %H:%M:%S", $time_str) }}
<?php $T = new Blitz('tpl'); $time_num = mktime(11, 22, 33, 7, 22, 1976); $time_str = '1976-07-22 01:02:03'; $T->set(array( 'time_num' => $time_num, 'time_str' => $time_str )); echo $T->parse(); ?>
22 07 1976 12:22:33 22 07 1976 05:02:03
(blitz ≥ 0.4.4)
escape — преобразовать специальные символы в сущности HTMLВ режиме по умолчанию, ENT_QUOTES
, преобразуются и двойные, и одиночные кавычки, а в режиме ENT_COMPAT
только двойные кавычки.
Пример 23. escape
{{escape($a)}} {{escape($b)}} {{escape($c, 'ENT_COMPAT')}}
<?php $T = new Blitz('tpl'); $T->set( array( 'a' => "this is 'a' \"test\"", 'b' => '<a href="null">', 'c' => '<>@#$%^&*()_=\'"' ) ); echo $T->parse(); ?>
this is 'a' "test" <a href="null"> <>@#$%^&*()_='"
(blitz ≥ 0.1)
if — отобразить в зависимости от истинности предиката либо один аргумент, либо другойПример 24. if
{{ $num }}. {{ $name }} {{ if($rip,'[R.I.P.]') }}
<? $T = new Blitz('tpl'); $character = array( array(1,'The Dude',0), array(2,'Walter Sobchak',0), array(3,'Donny',1), array(4,'Maude Lebowski',0), array(5,'The Big Lebowski',0), array(6,'Brandt',0), array(7,'Jesus Quintana',0), ); foreach ($character as $i => $data) { echo $T->parse( array( 'num' => $data[0], 'name' => $data[1], 'rip' => $data[2] ) ); } ?>
1. The Dude 2. Walter Sobchak 3. Donny [R.I.P.] 4. Maude Lebowski 5. The Big Lebowski 6. Brandt 7. Jesus Quintana
В данном примере использована укороченная форма if.
(blitz ≥ 0.1)
include — подключение другого шаблонаПример 25. include
1.tpl
В чем {{ include('2.tpl') }} жизни?
2.tpl
смысл
<?php $Template = new Blitz('1.tpl'); echo $Template->parse(); ?>
В чем смысл жизни?
Политика области видимости переменных очень проста: глобальные переменные видны в подключенном шаблоне, а локальные нет.