Содержание Blitz родился весьма неоригинально, for fun. Однако, поигравшись с ним
немного, мне показалось, что скорость, с которой он работает, и удобства,
которые он предоставляет разработчику - стоят того, чтобы дать его поиграться
коллегам. Основных "фишек" у Blitz три: Blitz поддерживает разделение и скрытие функционально различных частей шаблонов
с помощью простого механизма: текст шаблона может содержать вызов пользовательского
метода объекта, который этим шаблоном управляет. Таким образом достигается основная цель:
шаблон не содержит большого количества блоков и контекстов, часто мешающих разобраться,
что к чему. Напротив, даже в проекте со сложной логикой представления при правильном подходе
шаблоны будут давать разработчику своеобразную "карту" всего проекта.
Blitz также позволяет включать одни шаблоны в другие (аналог include) и поддерживает условный
вывод переменных (аналог if).
Начиная с версии 0.4 в blitz добавлен функционал движка php_templates. Теперь в blitz
можно создавать множество вложенных шаблонов внутри одного файла, это сильно упрощает жизнь
для очень сложных шаблонов с одной стороны и улучшает показатели по производительности
для ряда задач с другой. Также с версии 0.4 есть экспериментальная поддержка работы с набором
"упакованных" шаблонов (blitzpack), когда несколько шаблонов сначала единожды "компилируются"
в бинарный формат, упаковываются в один файл, и затем работа ведется только с этой
"бинарной пачкой" шаблонов, экономя время на файловых операциях и разборе шаблонов.
Мне бы не хотелось здесь следовать академической традиции и проводить подробный анализ
других проектов. В любом случае, если вы научились эффективно использовать сам PHP в качестве
шаблонного движка, обходясь без сторонних продуктов и библиотек - вы счастливый человек.
Вы используете самый эффективный с точки зрения производительности подход, и если он вам
удобен - придерживайтесь его. Если нет - попробуйте Blitz. Возможно, он вас приятно удивит ;)
Статус проекта - полуэкспериментальный, но я считаю текущую версию вполне работоспособной.
В силу параноидального отношения к качеству проекта, 100%-я стабильность и обратная совместимость
до версий 1.0 не гарантируется.
С сожалению, мне неизвестна ни одна простая, универсальная и по-настоящему корректная методика анализа
производительности шаблонных движков. А результатами любых искуственных, или как их
ещё принято называть, синтетических, тестов пользоваться нужно максимально осторожно.
Тем не менее, здесь приводятся результаты двух тестов. Первый тест - классический,
измеряющий скорость выполнения циклических итераций одного и того же шаблона.
Тест крайне простой, но позволяющий достаточно условно разделить группы движков
на "нормальные", "медленные" и "никуда не годные". Число итераций и переменных в блоке
было взято по умолчанию (9 переменных, 50 итераций), результаты этого теста приведены
в таблице 1. Как легко видеть, Blitz по крайней мере аутсайдером не является.
тбл. 1
Тестовая машина(B): PC PIV 2,8GHz (HT off) 1GB; linux-2.6.8 php-4.3.10 (Apache/1.3.33 static) zps
Столь сильное отличие php от прочих движков объясняется тем, что весь код php-теста
упакован в один файл, в то время для остальных есть два файла - php-файл контроллера и шаблонный файл,
который парсится котроллером.
В результаты этого теста не включены некоторые известные шаблонные движки,
такие как madtemplate, PEAR::Sigma и PEAR::HTML_Template_IT по простой причине: они
не были установлены на тестовых машинах. Однако, насколько мне
известно, эти проекты не являются кандидатами на попадание
в пятерку лидеров. В этом можно убедиться, например, проведя
онлайн-тесты самостоятельно,
или скачав тестирущую программу.
Второй тест более приближен к полевым условиям. Он представляет собой тестирование
некоторой динамической страницы, подготовленной с использованием разных движков, при помощи
стардартной утилиты ab. Итак, у нас есть страница какого-то псевдо-портала, содержащая:
Для тестирования было выбрано 4 подхода:
Все данные упакованы в структуру в отдельном файле, который инклюдится во всех тестовых вариантах.
Числа запросов в секунду, которое выполняет сервер для каждого из методов, представлены в таблице 2.
тбл. 2 Следует также принять во внимание, что в реальном проекте
разница в скорости между различными методами скорее всего будет ещё меньше.
Во-первых это связано с тем, что значительное время будет тратиться на работу с
источниками данных (СУБД, различные сервисы и проч.). Во-вторых, отношение "количества"
кода, относящегося к уровню представления, и прочего кода будет совершенно иным. Грубо
говоря, view_code = full_code для тестов и пусть выигрыш на синтетическом
тесте составляет даже десятки процентов. Но в реальном проекте часто выполняется
соотношение view_code << full_code, и поэтому выигрыш на уровне представления
уже почти ничего не даст. Как вы могли заметить, почти все тесты были проведены
с использованием акселератора из ZPS. Вряд ли сейчас можно представить крупный проект,
в котором не используется акселератор, однако, акселератор акселератору рознь.
И вполне возможно вы получите совершенно иные результаты при использовании, например, eAccelerator'a.
В-общем, призываю вас не полагаться полностью на приведенные результаты.
Скачивайте тесты, экспериментируйте на реальных задачах, и выбирайте те решения, которые дают
выигрыш в вашем проекте.
Начиная с версии 0.4 в дистрибутив входит несколько тестов:
Сборка blitz тестировалась на Linux 2.6 (i386) и Windows XP (до ветки 0.4).
Пользователи Windows могут воспользоваться готовыми Win32-бинарниками (версии ветки 0.4 пока недоступны).
Переменные. Следующий код демонстрирует работу с переменными:
Спец-методы. Следующий код демонстрирует использование include:
Пользовательские методы. Возможность включать в шаблон пользовательские методы -
самая интересная с точки зрения организации хорошего и удобно читаемого кода. До сих пор
в примерах использовался стандартный класс Blitz, никакими новыми методами не обладающий.
Однако, если создать объект класса-наследника Blitz, который предоставляет некоторый
метод my_test, в шаблоне можно использовать вызов этого метода ровно с таким же названием:
Все, что возвращает пользовательский метод будет сконвертировано в строку и подставлено вместо вызова.
Если вызов метода в шаблоне есть, но самого метода нет - будет подставлена пустая строка.
Вообще, действует обычное правило: никаких исходных вызовов
никогда не присутсвует в конечном результате, независимо от существования переменной,
метода и проч.
Внутри пользовательского метода также можно включать другие шаблоны. Конечно,
никто не запрещает вам написать что-нибудь вроде:
Этот метод будет работать, но не очень хорош по двум причинам. Во-первых, $TItem является совершенно
отдельным объектом, никак не связанным с $T. Blitzу несколько сложнее переключаться с одного объекта
на другой, нежели выполнять все операции через один и тот же объект. Во-вторых, $TItem не будет наследовать
установленные переменные из $T, их при необходимости нужно будет протягивать самостоятельно,
а также внутри $TItem нельзя использовать методы $T.
Поэтому более правильным будет использование встроенного метода include:
Начиная с версии 0.3 в blitz поддерживается передача параметров из шаблона в пользовательский метод:
Контексты. Начиная с версии 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.
А итерировать фактически означает "исполнить".
Следующий код выводит Следующий пример демонстрирует работу с простыми списками
Метод block - удобная замена последовательным iterate и set, которые встречаются в коде очень часто именно вместе.
Разумеется, в Blitz внутри контекста можно использовать и include, и if, и пользовательские методы. Переменные, установленные
в родительских контекстах, "не видны" в дочерних. Если есть необходимость в глобальных переменных, которые будут
"видны" в любом месте шаблона - можно использовать метод set_globals вместо set.
Следующий пример показывает, как при помощи вложенных конекстов строить более сложные списки.
Фактически на это простом механизме попеременных итераций вложенных котекстов реализуется абсолютно
любая логика даже в одном единственном шаблоне.
Для того, чтобы иметь возможность разделять шаблоны, и использовать контент
одного шаблона при работе с другим шаблоном, и даже более того, тело одного контекста в одном шаблоне внутри
другого, можно использовать метод fetch:
Вместо того, чтобы "очистить" каким-либо образом предыдущую итерацию контекста offline (такой функционал будет
добавлен в blitz в самое ближайшее время), создается новая итерация. Метод fetch получает результат исполнения
последней итерации контекста. В-общем, функционал контекстов достаточно мощный для того, что бы использовать шаблонный движок
для сколь угодно сложных проектов. В blitz внутри контектов также доступны такие приятные мелочи как if, include и вызов
метода контроллера.
Наконец, можно использовать метод load, чтобы загрузить тело шаблона из обычной php-переменной:
Зачем ещё один парсер шаблонов?
Некоторые результаты тестов производительности
Инсталляция
Вводный курс
Параметры настройки
Синтаксис Blitz и API
Зачем ещё один парсер шаблонов?
- написан как PHP-модуль на Си, и является одним из самых быстрых движков
- имеет простой и интуитивно понятный синтаксис
- позволяет структурировать код удобным и легко читаемым образом
Некоторые результаты тестов производительности
Тестовая машина(A): сервер XEON*2 2,4GHz (HT on) 2GB; linux php-4.3.10(fgci) zps nginx
blitz, php_templates: so-модули, CFLAGS: -g3 -O2
------------------------------------------------------
N 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%
blitz, php_templates: so-модули, CFLAGS -g -O2
----------------------------------------------------------
N 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%
- ротирующиеся рекламные уши (3 шт)
- "полосатую" навигацию (~10 разделов)
- горячие новости (~10 шт)
- список пользователи онлайн (~20 шт)
- голосовалка с вариантами ответов (3 ответа)
- прочие переменные на странице (~5 шт)
Тестовая машина(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
ab -n20000 -c100, ZPS off
################################
ugly php mess: 660
blitz ctx arrays: 590
blitz ctx: 560
php_templates: 450
blitzpack: 440
blitz includes: 430
php includes: 285
smarty: 125
К сожалению, я не имел возможности провести тесты для других шаблонных движков
(впрочем, код для этого теста доступен,
вы можете добавить в него решения исходной задачи с иcпользованием любых других средств).
Поэтому ограничусь обобщенной интерпретацией этих результатов. То, что native PHP-код вместе
с акселератором всегда будут быстрее прочих решений - очевидно. Правда, следует особенно
подчеркнуть, что native в этом смысле - именно написанный программистом самим,
а не "скомпилированный". В этом легко убедиться, заглянув внутрь любого
"скомпилированного" шаблона: как правило, их код состоит из многомерных,
довольно сложных для выполнения конструкций, значительно сложнее, чем написанный
правильными руками код ;) Поскольку разница между blitz и "правильным" методом
php includes не является кардинальной, а все синтетические тесты позволяют лишь
выявить группы приблизительно равных, можно с определенной долей уверенности считать методы
разработки с использованием php, blitz и php_templates примерно одинаковыми
по производительности.
Инсталляция
Blitz - расширение PHP, поставляемое пока исключительно в исходных кодах,
поэтому его инсталляция состоит из обычных шагов по сборке расширешия:
bash> tar zxvf blitz.tar.gz
bash> cd blitz
bash> phpize
bash> make
bash> ./configure
bash> make install
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, являются собственно шаблон и объект, управляющий
выполнением этого шаблона (контроллер шаблона).
В шаблоне допускаются три вида конструкций
Ex. 1, file ex1A.tpl:
Это некоторый тест для двух переменных: {{ $a }} и {{ $b }}, номер итерации: {{ $i }}
Ex. 1, file ex1B.php
<?
$T = new Blitz('ex1A.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
)
);
}
?>
Ex.1 Output:
Это некоторый тест для двух переменных: 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 - внутренний класс расширения, управляющий шаблоном. Первый и единственный аргумент
конструктора класса - имя шаблона. Вместо вызова parse($arr_params) вы можете использовать
set($arr_params) и parse() без аргументов.
Ex. 2, file ex2A.tpl:
Мама {{ include('ex2B.tpl') }} раму
Ex. 2, file ex2B.tpl:
мыла
Ex. 2, file ex2С.php:
<?
$T = new Blitz('ex2A.tpl');
echo $T->parse();
echo "\n";
?>
Ex.2 Output:
Мама мыла раму
Если вы включаете один шаблон в другой, то включаемый шаблон наследует все переменные внешнего шаблона:
Ex. 3, file ex3A.tpl:
переменная a = {{ $a }}
внутренний шаблон: {{ include('ex3B.tpl') }}
переменная b = {{ $b }}
Ex. 3, file ex3B.tpl:
/* переменная a = {{ $a }}, переменная b = {{ $b }} */
Ex. 3, file ex3С.php:
<?
$T = new Blitz('ex3A.tpl');
$T->set(array('a' => 'a_value', 'b' => 'b_value'));
echo $T->parse();
echo "\n";
?>
Ex.3 Output:
переменная a = a_value
внутренний шаблон: /* переменная a = a_value, переменная b = b_value */
переменная b = b_value
В шаблоне также можно использовать псевдо-оператор if. На самом деле, это такой же спец-метод,
отображающий в зависимости от истинности предиката либо один аргумент, либо другой. Cуществует
укороченная форма if, без третьего аргумента - аналогичная полной форме с пустым третьим аргументом:
if($a,$b) = if($a,$b,'');
Ex. 4, file ex4A.tpl:
{{ $num }}. {{ $name }} {{ if($rip,'[R.I.P.]') }}
Ex. 4, file ex4B.php:
<?
T = new Blitz('ex4A.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]
)
);
}
?>
Ex.4 Output:
1. The Dude
2. Walter Sobchak
3. Donny [R.I.P.]
4. Maude Lebowski
5. The Big Lebowski
6. Brandt
7. Jesus Quintana
В данном примере использована укороченная форма if.
Ex 5, file ex5a.tpl:
пример вызова пользовательского метода: {{ my_test }}
Ex 5, file ex5B.php:
<?
class BlitzTemplate extends Blitz {
function BlitzTemplate($t) {
parent::Blitz($t);
}
function my_test() {
return 'user method called ('.__CLASS__.','.__LINE__.')';
}
}
$T = new BlitzTemplate('ex5A.tpl');
echo $T->parse();
?>
Ex 5, Output:
пример вызова пользовательского метода: user method called (blitztemplate,10)
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();
Ex.6, file ex6A.tpl:
parent value: {{ $parent_val }}
child_value: {{ $child_val }}
===========================================================
{{ test_include }}
===========================================================
parent value: {{ $parent_val }}
child_value: {{ $child_val }}
Ex.6, file ex6B.tpl:
parent method: {{ my_test }}
child value: {{ $child_val }}
parent value: {{ $parent_val }}
Ex.6, file ex6C.php:
<?
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('ex6A.tpl','ex6B.tpl');
echo $T->parse();
?>
Ex.6, Output:
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 добавляются
к уже установленным параметрам шаблона, и уже после этого происходит выполнение кода,
поэтому ничего удивительного в таком поведении нет. Эту особенность следует иметь ввиду,
чтобы случайно не "затереть" ранее установленную переменную.
Ex.7, file ex7A.tpl:
calling template with arguments: {{ my_test(134,$x,"hello,world!",$dummy) }}
Ex.7, file ex7B.php:
<?
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('ex7A.tpl');
echo $T->parse();
?>
Ex. 7, Output:
calling template with arguments: user method called (blitztemplate,12)
parameters are:
1:134
2:1234
3:'hello,world!'
4:NULL
ужасно доставшее всех знакомое всем приветствие, запрятанное в трёх вложенных контекстах.
tree.tpl:
{{ BEGIN root }}
{{ BEGIN node }}
{{ BEGIN item }}
hello, world
{{ END }}
{{ END }}
{{ END }}
код:
$T = new Blitz('tree.tpl');
$T->iterate('/root/node/item');
echo $T->parse();
ex8A.tpl:
{{ BEGIN row }}row #{{ $i }}
{{ END }}
ex8B.php:
$T = new Blitz('ex8A.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();
Ex. 8, Output:
row #0
row #1
row #2
row #3
row #4
row #0
row #1
row #2
row #3
row #4
ex9A.tpl:
complex list example
{{ BEGIN list; }}
list #{{ $list_num }}
{{ BEGIN list_empty; }} this list is empty {{ END }}{{ BEGIN list_item; }} row #{{ $i_row; }}
{{ END }}
{{ END }}
ex9B.php:
$T = new Blitz('ex9A.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();
Ex. 9, Output:
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
ex10A.tpl:
{{ 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 }}
ex10B.php:
$T = new Blitz('ex10A.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";
Ex. 10, Output:
online!
away...
was online 15 days ago
was online 2 months ago
ex11A.php:
$body = <<<BODY
hello, {{ \$who }}!
{{ bye; }}
BODY;
class View extends Blitz {
function bye() {
return "Have a lot of fun!...";
}
}
$T = new View();
$T->load($body);
echo $T->parse(array('who' => 'world'));
Ex. 11, Output:
hello, world!
Have a lot of fun!...
Параметры настройки
Вы можете изменять следующие параметры настройки (php.ini):
Синтаксис Blitz и API
under construction ;)