Содержание
Список таблиц
Список примеров
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(fgci) 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 |
smarty | 285 |
php includes | 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
make
./configure
make install
Начиная с версии 0.4 в дистрибутив входит несколько тестов:
bash>./run-tests.sh ===================================================================== CWD : /distr/php-5.2.0/ext/blitz/tests PHP : /home/php-5.2.0/bin/php PHP_SAPI : cli PHP_VERSION : 5.2.0 ZEND_VERSION: 2.2.0 PHP_OS : Linux - Linux fisher 2.6.11.4-20a-smp #1 SMP Wed Mar 23 21:52:37 UTC 2005 i686 INI actual : /home/php-5.2.0/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 has context [has_context.phpt] PASS predefined methods: if [if.phpt] PASS predefined methods: include [include.phpt] PASS ini-values settings test [ini.phpt] PASS user-defined methods [method.phpt] PASS method call from inner include [mfi.phpt] PASS mix #1 [mix1.phpt] PASS mix #2 [mix2.phpt] PASS mix #3 [mix3.phpt] PASS mix #4 [mix4.phpt] PASS mix #5 [mix5.phpt] PASS mix #6 [mix6.phpt] PASS expect regexp test [regex.phpt] PASS returning non-strings from user methods [return_non_string.phpt] PASS set and get [set_and_get.phpt] PASS variables [var.phpt] ===================================================================== Number of tests : 20 20 Tests skipped : 0 ( 0.0%) -------- Tests warned : 0 ( 0.0%) ( 0.0%) Tests failed : 0 ( 0.0%) ( 0.0%) Tests passed : 20 (100.0%) (100.0%) --------------------------------------------------------------------- Time taken : 0 seconds =====================================================================
После этого вы, возможно, захотите отредактировать свой php.ini, включив blitz в список расширений:
extension=blitz.so
Сборка blitz тестировалась на Linux 2.6 (i386) и Windows XP. Пользователи Windows могут воспользоваться готовыми Win32-бинарниками.
Содержание
Как и во многих других шаблонных движках двумя базовыми сущностями проекта, которые использует Blitz, являются собственно шаблон и объект, управляющий выполнением этого шаблона (контроллер шаблона).
Класс Blitz
— внутренний класс расширения, управляющий шаблоном. Первый и единственный аргумент конструктора класса — имя шаблона.
Пример 5.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
, никакими новыми методами не обладающий. Однако если создать объект класса-наследника Blitz
, который предоставляет некоторый метод my_test
, в шаблоне можно использовать вызов этого метода ровно с таким же названием.
Пример 6.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 поддерживается передача параметров из шаблона в пользовательский метод.
Пример 6.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
Начиная с версии 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()
и вызов пользовательского метода.
Следующий код выводит ужасно доставшее всех знакомое всем приветствие, запрятанное в трех вложенных контекстах.
Пример 7.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
Пример 7.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()
, и пользовательские методы. Переменные, установленные в родительских контекстах, «не видны» в дочерних. Если есть необходимость в глобальных переменных, которые будут «видны» в любом месте шаблона - можно использовать метод set_global()
вместо set()
.
Пример 7.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 >= 0.4)
context — установка контекстаПример 8. 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)
dump_iterations — дамп итерацийПример 9. dump_iterations
{{BEGIN counter}} {{$i}}, {{END}}
<?php $Template = new Blitz('tpl'); for ($i = 0; $i < 3; $i++) { $Template->block('context', array('i' => $i)); } $Template->dump_iterations(); ?>
ITERATION DUMP (4 parts) (1) iterations: array(1) { [0]=> array(1) { ["context"]=> array(1) { [0]=> array(1) { ["i"]=> int(0) } } } } (2) current path is: / (3) current node data (current_iteration_parent) is: array(1) { [0]=> array(1) { ["context"]=> array(1) { [0]=> array(1) { ["i"]=> int(0) } } } } (4) current node item data (current_iteration) is: empty ITERATION DUMP (4 parts) (1) iterations: array(1) { [0]=> array(1) { ["context"]=> array(2) { [0]=> array(1) { ["i"]=> int(0) } [1]=> array(1) { ["i"]=> int(1) } } } } (2) current path is: / (3) current node data (current_iteration_parent) is: array(1) { [0]=> array(1) { ["context"]=> array(2) { [0]=> array(1) { ["i"]=> int(0) } [1]=> array(1) { ["i"]=> int(1) } } } } (4) current node item data (current_iteration) is: empty ITERATION DUMP (4 parts) (1) iterations: array(1) { [0]=> array(1) { ["context"]=> 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) { ["context"]=> 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: empty
См. также dump_struct()
.
(blitz >= 0.4)
dump_struct — дамп структурыПример 10. dump_struct
{{BEGIN counter}} {{$i}}, {{END}}
<?php $Template = new Blitz('tpl'); for ($i = 0; $i < 3; $i++) { $Template->block('context', array('i' => $i)); } $Template->dump_struct(); ?>
== 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));
См. также dump_iterations()
.
(blitz >= 0.4)
fetch — использовать контент одного шаблона при работе с другим шаблоном или тело одного контекста в одном шаблоне внутри другогоПример 11. 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"; $T->iterate(); // create next iteration for offline block // 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
Вместо того чтобы «очистить» каким-либо образом предыдущую итерацию контекста offline (такой функционал будет добавлен в Blitz в самое ближайшее время), создается новая итерация. Метод fetch получает результат исполнения последней итерации контекста.
(blitz >= 0.4)
iterate — итерация контекстаПример 13. 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 — разбор шаблонаПример 15. parse без установки переменных
Hello, world!
<?php $Template = new Blitz('tpl'); echo $Template->parse(); ?>
Hello, world!
Пример 16. parse с установкой переменных
Hello, {{$object}}!
<?php $Template = new Blitz('tpl'); echo $Template->parse(array('object' => 'world')); ?>
Hello, world!
(blitz >= 0.1)
set — установка переменныхПример 17. set
Hello, {{$object}}!
<?php $Template = new Blitz('tpl'); $Template->set(array('object' => 'world')); echo $Template->parse(); ?>
Hello, world!
Пример 18. 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>
Один такой здоровый массив описывает N итераций, причем массивы могут быть любого уровня вложенности — короче можно не вызывать context/iterate/set, а сначала «приготовить» такую вот структуру данных, а потом одним махом засадить эти итерации в шаблон — иногда это удобно (к примеру, вместе с PDO::fetchAll(PDO::FETCH_ASSOC)
) и вообще говоря, это работает очень быстро (blitz ctx arrays в benchmarks).
См. также set_global()
, block()
.
(blitz >= 0.4)
set_global — установка глобальных переменныхПример 19. set_global
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->set_global(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.1)
if — отобразить в зависимости от истинности предиката либо один аргумент, либо другойПример 20. 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 — подключить шаблонПример 21. include
1.tpl
Мама {{ include('other.tpl') }} раму
2.tpl
мыла
<? $T = new Blitz('tpl'); echo $T->parse(); echo "\n"; ?>
Мама мыла раму
Если вы включаете один шаблон в другой, то включаемый шаблон наследует все переменные внешнего шаблона.
Пример 22. include: наследование всех переменных внешнего шаблона
1.tpl
переменная a = {{ $a }} внутренний шаблон: {{ include('other.tpl') }} переменная b = {{ $b }}
2.tpl
/* переменная a = {{ $a }}, переменная b = {{ $b }} */
<? $T = new Blitz('tpl'); $T->set(array('a' => 'a_value', 'b' => 'b_value')); echo $T->parse(); echo "\n"; ?>
переменная a = a_value внутренний шаблон: /* переменная a = a_value, переменная b = b_value */ переменная b = b_value
Пример 23. Иcпользование встроенного метода include лучше создания наследников Blitz лишь ради include
1.tpl
parent value: {{ $parent_val }} child_value: {{ $child_val }} =========================================================== {{ test_include }} =========================================================== parent value: {{ $parent_val }} child_value: {{ $child_val }}
2.tpl
parent method: {{ my_test }} child value: {{ $child_val }} parent value: {{ $parent_val }}
<? class BlitzTemplate extends Blitz { var $titem; function BlitzTemplate($t,$titem) { parent::Blitz($t); $this->set(array('parent_val' => 'some_parent_val')); $this->titem = $titem; } function my_test() { return 'user method called ('.__CLASS__.','.__LINE__.')'; } function test_include() { $result = ''; while($i++<3) { $result .= $this->include($this->titem,array( 'child_val' => 'i_'.$i )); } return $result; } } $T = new BlitzTemplate('tpl','other.tpl'); echo $T->parse(); ?>
parent value: some_parent_val child_value: =========================================================== parent method: user method called (blitztemplate,13) child value: i_1 parent value: some_parent_val parent method: user method called (blitztemplate,13) child value: i_2 parent value: some_parent_val parent method: user method called (blitztemplate,13) child value: i_3 parent value: some_parent_val =========================================================== parent value: some_parent_val child_value: i_3
При первой обработке шаблона структура всех его тэгов сохраняется, поэтому при последующих вызовах шаблон снова не анализируется. Обратите внимание на то, что до выполнения метода test_include переменная child_value пуста и не «видна» в шаблоне, но после выполнения видна и содержит последнее установленное значение. Это поведение аналогично тому, что происходит при выполнении php-кода, если бы вместо test_include у нас был include некоторого php-файла, внутри которого бы инициализировалась новая переменная. Внутри внешнего кода до include она имела бы неопределенное значение, но после - уже нет. На самом деле при вызове include сначала все параметры вызова include добавляются к уже установленным параметрам шаблона, и уже после этого происходит выполнение кода, поэтому ничего удивительного в таком поведении нет. Эту особенность следует иметь в виду, чтобы случайно не «затереть» ранее установленную переменную.