Товарищ! Русская дока безнадежно устарела! Не читай её! Делай, что говорит королева, не увеличивай энтропию.




















Blitz Templates

Alexey Rybak

Vladimir Krivosheev

Быстрый шаблонизатор для очень больших интернет-проектов

Загрузка, исходники

Other languages: english

Обратная связь: список рассылки blitz-subscribe aT alexeyrybak d0t com или BugTraker


Содержание

I. Введение
1. Зачем еще один парсер шаблонов?
2. Некоторые результаты тестов производительности
II. Установка и настройка
3. Установка
4. Настройка
III. Справочник языка
5. Основы синтаксиса
6. Контексты
7. Типы
8. Пользовательские методы
9. Переменные
IV. Методы
I. Контроллер
block — итерировать и установить контекст
clean — очистить переменные и итерации контекста
context — установить контекст
dumpIterations — дамп итераций
dumpStruct — дамп структуры
fetch — использовать контент одного шаблона при работе с другим шаблоном или тело одного контекста в одном шаблоне внутри другого
hasContext — проверить существование контекста
include — подключение другого шаблона
iterate — итерировать контекст
load — загрузить тело шаблона из переменной PHP
parse — разобрать шаблон
set — установить переменные
setGlobal — установить глобальные переменные
II. Шаблон
date — форматировать дату/время
escape — преобразовать специальные символы в сущности HTML
if — отобразить в зависимости от истинности предиката либо один аргумент, либо другой
include — подключение другого шаблона

Список таблиц

2.1. Классический тест производительности
2.2. Тест производительности приближенный к полевым условиям
4.1. Параметры конфигурации

Список примеров

6.1. Ужасно доставшее всех знакомое всем приветствие, запрятанное в трех вложенных контекстах
6.2. Работа с простыми списками
6.3. Как при помощи вложенных контекстов строить более сложные списки
8.1. Вызов пользовательского метода
8.2. Передача параметров из шаблона в пользовательский метод
9.1. Переменные
7. block
8. clean
9. context
10. dumpIterations
11. dumpStruct
12. fetch
13. hasContext
14. include
15. iterate
16. load
17. parse без установки глобальных переменных
18. parse с установкой глобальных переменных
19. set
20. set как «быстрый» способ установить целый массив итераций
21. setGlobal
22. date
23. escape
24. if
25. include

Часть I. Введение

Глава 1. Зачем еще один парсер шаблонов?

Blitz родился весьма неоригинально, for fun. Однако, поигравшись с ним немного, мне показалось, что скорость, с которой он работает, и удобства, которые он предоставляет разработчику — стоят того, чтобы дать его поиграться коллегам. Основных «фишек» у Blitz три:

  • написан как PHP-модуль на Си, и является одним из самых быстрых движков;

  • имеет простой и интуитивно понятный синтаксис;

  • позволяет структурировать код удобным и легко читаемым образом.

Blitz поддерживает разделение и скрытие функционально различных частей шаблонов с помощью простого механизма: текст шаблона может содержать вызов методов объекта, который этим шаблоном управляет. Таким образом, достигается основная цель: шаблон не содержит большого количества блоков и контекстов, часто мешающих разобраться, что к чему. Напротив, даже в проекте со сложной логикой представления при правильном подходе шаблоны будут давать разработчику своеобразную «карту» всего проекта. Blitz также позволяет включать одни шаблоны в другие (аналог include) и поддерживает условный вывод переменных (аналог if).

Начиная с версии 0.4 в Blitz добавлен функционал движка php_templates. Теперь в Blitz можно создавать множество вложенных шаблонов внутри одного файла, это сильно упрощает жизнь для очень сложных шаблонов с одной стороны и улучшает показатели по производительности для ряда задач с другой.

Также с версии 0.4 есть экспериментальная поддержка работы с набором «упакованных» шаблонов (blitzpack), когда несколько шаблонов сначала единожды «компилируются» в бинарный формат, упаковываются в один файл, и затем работа ведется только с этой «бинарной пачкой» шаблонов, экономя время на файловых операциях и разборе шаблонов.

Мне бы не хотелось здесь следовать академической традиции и проводить подробный анализ других проектов. В любом случае, если вы научились эффективно использовать сам PHP в качестве шаблонного движка, обходясь без сторонних продуктов и библиотек — вы счастливый человек. Вы используете самый эффективный с точки зрения производительности подход, и если он вам удобен — придерживайтесь его. Если нет — попробуйте Blitz. Возможно, он вас приятно удивит ;)

Внимание

Статус проекта — полуэкспериментальный, но я считаю текущую версию вполне работоспособной. В силу параноидального отношения к качеству проекта, 100%-я стабильность и обратная совместимость до версии 1.0 не гарантируется.

Глава 2. Некоторые результаты тестов производительности

К сожалению, мне неизвестна ни одна простая, универсальная и по-настоящему корректная методика анализа производительности шаблонных движков. А результатами любых искусственных, или как их ещё принято называть, синтетических, тестов пользоваться нужно максимально осторожно. Тем не менее, здесь приводятся результаты двух тестов. Первый тест — классический, измеряющий скорость выполнения циклических итераций одного и того же шаблона. Тест крайне простой, но позволяющий достаточно условно разделить группы движков на «нормальные», «медленные» и «никуда не годные». Число итераций и переменных в блоке было взято по умолчанию (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 nameTimePercentage
1php0.000544100%
2blitz0.001008185%
3php_templates0.001812333%
4smarty0.002006369%
5str_replace0.003713683%
6phemplate0.004514830%
7fasttemplate0.0068351256%
8vtemplate0.0095651758%
9ultratemplate0.0129932388%
10templatepower0.0170563135%
11bugitemplate0.0199893674%
12phplib0.0280535157%
13profTemplate0.0431047924%
14xtemplate0.0487998970%
Тестовая машина (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 nameTimePercentage
1php0.00045100%
2blitz0.000834185%
3php_templates0.001595354%
4smarty0.001694376%
5str_replace0.00373829%
6phemplate0.004215937%
7fasttemplate0.0061391364%
8vtemplate0.0087551946%
9ultratemplate0.0127472833%
10templatepower0.0186784151%
11bugitemplate0.0192864286%
12phplib0.0254785662%
13profTemplate0.04514810033%
14xtemplate0.04813710697%

Столь сильное отличие 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 mess1150
blitz ctx arrays890
blitz ctx825
php includes770
blitzpack725
blitz incudes680
smarty620
php_templates615
Тестовая машина(B), см. таблицу 1
ab -n20000 -c100, ZPS off
ugly php mess660
blitz ctx arrays590
blitz ctx560
php_templates450
blitzpack440
blitz incudes430
php includes285
smarty125

К сожалению, я не имел возможности провести тесты для других шаблонных движков (впрочем, код для этого теста доступен, вы можете добавить в него решения исходной задачи с использованием любых других средств). Поэтому ограничусь обобщенной интерпретацией этих результатов. То, что native PHP-код вместе с акселератором всегда будут быстрее прочих решений — очевидно. Правда, следует особенно подчеркнуть, что native в этом смысле — именно написанный программистом самим, а не «скомпилированный». В этом легко убедиться, заглянув внутрь любого «скомпилированного» шаблона: как правило, их код состоит из многомерных, довольно сложных для выполнения конструкций, значительно сложнее, чем написанный правильными руками код ;) Поскольку разница между Blitz и «правильным» методом php includes не является кардинальной, а все синтетические тесты позволяют лишь выявить группы приблизительно равных, можно с определенной долей уверенности считать методы разработки с использованием PHP, Blitz и php_templates примерно одинаковыми по производительности.

Следует также принять во внимание, что в реальном проекте разница в скорости между различными методами, скорее всего, будет ещё меньше. Во-первых, это связано с тем, что значительное время будет тратиться на работу с источниками данных (СУБД, различные сервисы и проч.). Во-вторых, отношение «количества» кода, относящегося к уровню представления, и прочего кода будет совершенно иным. Грубо говоря, view_code = full_code для тестов и пусть выигрыш на синтетическом тесте составляет даже десятки процентов. Но в реальном проекте часто выполняется соотношение view_code >> full_code, и поэтому выигрыш на уровне представления уже почти ничего не даст. Как вы могли заметить, почти все тесты были проведены с использованием акселератора из ZPS. Вряд ли сейчас можно представить крупный проект, в котором не используется акселератор, однако, акселератор акселератору рознь. И вполне возможно вы получите совершенно иные результаты при использовании, например, eAccelerator'a. В-общем, призываю вас не полагаться полностью на приведенные результаты. Скачивайте тесты, экспериментируйте на реальных задачах, и выбирайте те решения, которые дают выигрыш в вашем проекте.

Часть II. Установка и настройка

Глава 3. Установка

Blitz — расширение PHP, поставляемое пока исключительно в исходных кодах, поэтому его установка состоит из обычных шагов по сборке расширения:

  1. tar zxvf blitz.tar.gz

  2. cd blitz

  3. phpize

  4. ./configure

  5. make

  6. make install

Вы можете протестировать Blitz запустив скрипт run-tests.sh.

Внимание

Вы должны отредактировать данный файл для изменения пути к стандартной тестовой процедуре PHP 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. Настройка

Таблица 4.1. Параметры конфигурации

ИмяОписаниеЗначение по умолчаниюИзменяемость
blitz.tag_openоткрывающий тег{{PHP_INI_ALL
blitz.tag_close закрывающий тег}}PHP_INI_ALL
blitz.var_prefixпрефикс переменной$PHP_INI_ALL

Подсказка

Для вывода переменной шаблона $test, вы должны вставить следующий код в ваш шаблон: {{ $test }}

Часть III. Справочник языка

Глава 5. Основы синтаксиса

Как и во многих других шаблонных движках двумя базовыми сущностями проекта, которые использует Blitz, являются собственно шаблон и объект, управляющий выполнением этого шаблона (контроллер шаблона).

Класс Blitz — внутренний класс расширения, управляющий шаблоном. Первый и единственный параметр конструктора класса — имя шаблона. Этот параметр необязателен — можно загрузить шаблон из переменной PHP используя метод load().

Blitz не поддерживает по принципиальным соображениям сложные выражения:

{{if(if($foo, 0, 1), 'bar', 'foobar')}}

Данный код работать не будет. Не надо превращать код в спагетти.

Глава 6. Контексты

Начиная с версии 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

Фактически на этом простом механизме попеременных итераций вложенных контекстов реализуется абсолютно любая логика даже в одном единственном шаблоне.

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

Глава 7. Типы

Blitz поддерживает 4 типа:

  • boolean (≥ 0.4.3)
  • integer
  • float
  • string

Типы аналогичны типам PHP, за исключением того, что нет разницы — заключена строка в двойные или одинарные кавычки.

Глава 8. Пользовательские методы

Возможность включать в шаблон пользовательские методы - самая интересная с точки зрения организации хорошего и удобно читаемого кода. До сих пор в примерах использовался стандартный класс 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

Глава 9. Переменные

Переменные представлены знаком 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

Часть IV. Методы

Содержание

I. Контроллер
block — итерировать и установить контекст
clean — очистить переменные и итерации контекста
context — установить контекст
dumpIterations — дамп итераций
dumpStruct — дамп структуры
fetch — использовать контент одного шаблона при работе с другим шаблоном или тело одного контекста в одном шаблоне внутри другого
hasContext — проверить существование контекста
include — подключение другого шаблона
iterate — итерировать контекст
load — загрузить тело шаблона из переменной PHP
parse — разобрать шаблон
set — установить переменные
setGlobal — установить глобальные переменные
II. Шаблон
date — форматировать дату/время
escape — преобразовать специальные символы в сущности HTML
if — отобразить в зависимости от истинности предиката либо один аргумент, либо другой
include — подключение другого шаблона

Контроллер

Содержание

block — итерировать и установить контекст
clean — очистить переменные и итерации контекста
context — установить контекст
dumpIterations — дамп итераций
dumpStruct — дамп структуры
fetch — использовать контент одного шаблона при работе с другим шаблоном или тело одного контекста в одном шаблоне внутри другого
hasContext — проверить существование контекста
include — подключение другого шаблона
iterate — итерировать контекст
load — загрузить тело шаблона из переменной PHP
parse — разобрать шаблон
set — установить переменные
setGlobal — установить глобальные переменные

block

(blitz ≥ 0.4)

block — итерировать и установить контекст

bool block ( string context_path [, array parameters ] )

Пример 7. block

{{BEGIN welcome}}
	Hello, {{$object}}!
{{END}}
<?php

$Template = new Blitz('tpl');
$Template->block('welcome', array('object' => 'world'));
echo $Template->parse();

?>
Hello, world!

См. также context(), iterate(), set().

clean

(blitz ≥ 0.4.10)

clean — очистить переменные и итерации контекста

bool clean ( [ string context_path = '/' [, bool warn_notfound = true ]] )

$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 ()
================================

context

(blitz ≥ 0.4)

context — установить контекст

bool context ( string context_path )

Пример 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().

dumpIterations

(blitz ≥ 0.4)

dumpIterations — дамп итераций

bool 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().

dumpStruct

(blitz ≥ 0.4)

dumpStruct — дамп структуры

bool 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().

fetch

(blitz ≥ 0.4)

fetch — использовать контент одного шаблона при работе с другим шаблоном или тело одного контекста в одном шаблоне внутри другого

string fetch ( string name [, array parameters ] )

Пример 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 получает результат исполнения последней итерации контекста.

Внимание

До версии 0.4.2 поведение fetch было неправильным — вы должны были вручную использовать iterate(), чтобы очистить извлеченные итерации. С версии 0.4.2 каждый вызов fetch автоматически очищает предыдущие итерации контекста.

hasContext

(blitz ≥ 0.4)

hasContext — проверить существование контекста

bool hasContext ( string context_path )

Псевдоним метода — has_context.

Пример 13. hasContext

{{BEGIN foo}}{{END}}
<?php

$Template = new Blitz('tpl');
var_dump($Template->hasContext('foo'));
var_dump($Template->hasContext('bar'));

?>
bool(true)
bool(false)

include

(blitz ≥ 0.1)

include — подключение другого шаблона

string include ( string template_name [, array global_vars ] )

Пример 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().

iterate

(blitz ≥ 0.4)

iterate — итерировать контекст

bool iterate ( [ string context_path ] )

Пример 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!

См. также block(), context().

load

(blitz ≥ 0.4)

load — загрузить тело шаблона из переменной PHP

bool load ( string tpl )

Пример 16. load

<?

$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'));

?>
hello, world!
Have a lot of fun!...

parse

(blitz ≥ 0.1)

parse — разобрать шаблон

string parse ( [ array global_vars ] )

Пример 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!

set

(blitz ≥ 0.1)

set — установить переменные

bool set ( array parameters )

Пример 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().

setGlobal

(blitz ≥ 0.4)

setGlobal — установить глобальные переменные

bool setGlobal ( array parameters )

Псевдоним метода — 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().

Шаблон

Содержание

date — форматировать дату/время
escape — преобразовать специальные символы в сущности HTML
if — отобразить в зависимости от истинности предиката либо один аргумент, либо другой
include — подключение другого шаблона

date

(blitz ≥ 0.4.11)

date — форматировать дату/время

string date ( string format [, int | string time = now ] )

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

escape

(blitz ≥ 0.4.4)

escape — преобразовать специальные символы в сущности HTML

string escape ( string string [, string quote_style = 'ENT_QUOTES' ] )

В режиме по умолчанию, 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 &#039;a&#039; &quot;test&quot;
&lt;a href=&quot;null&quot;&gt;
&lt;&gt;@#$%^&amp;*()_='&quot;

if

(blitz ≥ 0.1)

if — отобразить в зависимости от истинности предиката либо один аргумент, либо другой

string if ( string a , string b [, string c ] )

Пример 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.

include

(blitz ≥ 0.1)

include — подключение другого шаблона

string include ( string template_name )

Пример 25. include

1.tpl

В чем {{ include('2.tpl') }} жизни?

2.tpl

смысл
<?php

$Template = new Blitz('1.tpl');
echo $Template->parse();

?>
В чем смысл жизни?

Политика области видимости переменных очень проста: глобальные переменные видны в подключенном шаблоне, а локальные нет.