Blitz: шаблонный подход к построению контента

Мне кажется, что пора уже рассматривать тему шаблонизаторов - специальных библиотек для построения шаблонов. Проблема любого крупного проекта, я думаю, - отделение дизайна от кода (т.е. html-страниц от php-кода). Зачем это делать? Ну на то конечно есть причины. Во-первых, разделенные дизайн и код легче поддерживать и изменять.

Во-вторых, если на сайте нужна смена скинов, без шаблонов не обойтись, потому что для каждого скина придется дублировать все php-файлы (код), а это не есть хорошо (потому что отнимает много времени) для постоянно изменяющегося кода в результате воздействия заказчика :)

Так вот, существует множество шаблонизаторов, из которых я бы воспользовался одним из двух: Smarty и Blitz. О Smarty мы поговорим в других статьях, а в этой коснемся Blitz - шаблонизатора, о котором я совсем недавно узнал, в отличие от Smarty.

Blitz - шаблонизатор, написанный нашим соотечественником - Алексеем Рыбаком - на основе движка php_templates. Считается самым быстрым шаблонизатором на данный момент. Причина такого быстродействия - написан на языке Си (как модуль расширения PHP). Но у каждой вещи в этом мире есть свои достоинства и недостатки. Про главное достоинство Blitz я уже сказал, а главных недостатков я выделил у него три:

  1. На данный момент еще сыроват, т.к. не доделан даже до версии 1.0 (на момент написания этой статьи последняя версия была 0.6.1);
  2. Функционал не такой мощный, как в Smarty (этот недостаток можно едва компенсировать наличием механизма контекстов и итераций, которого нет у Smarty). Я бы сказал даже, Smarty гораздо мощнее;
  3. Библиотеку нужно устанавливать в качестве расширения PHP, что возможно не у всех хостинг-провайдеров.

Но, несмотря на эти недостатки, этот шаблонизатор стоит того, чтобы рассмотреть его возможности.

Установка Blitz

У меня, как Вы знаете (а может и не знаете), система Windows, поэтому я просто прикрутил модуль php_blitz.dll, ссылку на который можно найти здесь. В Linux как он устанавливается, я не знаю, но в официальной документации, которая состоит всего из одной странички, можно найти ссылку на исходники и готовые модули. Там же написано про то, как устанавливается этот Blitz.

Изучаем Blitz

Начнем с самого простого - выведем в окно браузера содержимое переменной:

example1.tpl

Содержимое переменной $a: {{$a}}<br />
Содержимое переменной $b: {{$b}}

example1.php

<?
    header('Content-Type: text/plain');

    $T = new Blitz('example1.tpl');
    $T->set(Array('b' => 'world'));
    echo $T->parse(Array('a' => 'Hello'));
?>

Вывод:

Содержимое переменной $a: Hello<br />
Содержимое переменной $b: world

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

Можно не передавать методу parse массив с глобальными переменными, а передать его отдельно методу setGlobal:

$T->setGlobal(Array(‘b’ => ‘world’));

Теперь покажу различие глобальных и локальных переменных в контекстах:

example2.tpl

Я {{$l}} переменная.<br />
Я {{$g}} переменная.<br />
{{BEGIN root}}<br />
    Я {{$l}} переменная.<br />
    Я {{$g}} переменная.<br />
{{END}}

example2.php

<?
    header('Content-Type: text/plain');

    $T = new Blitz('example2.tpl');
   
    $T->set(Array('l' => 'локальная в пределах шаблона'));
    $T->setGlobal(Array('g' => 'глобальная'));
    $T->block('/root', Array('l' => 'локальная в пределах контекста'));
   
    echo $T->parse();
?>

Вывод:

Я локальная в пределах шаблона переменная.<br />
Я глобальная переменная.<br />
    Я локальная в пределах контекста переменная.<br />
    Я глобальная переменная.

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

$T->block(‘/root’);

…, то вывод был бы таким:

Я локальная в пределах шаблона переменная.<br />
Я глобальная переменная.<br />
    Я  переменная.<br />
    Я глобальная переменная.

Т.е. локальная в пределах шаблона переменная не действует в зоне контекста, а глобальная переменная действует везде.

Если бы мы не вызвали block (не выполнили бы контекст), вывод был бы таким:

Я локальная в пределах шаблона переменная.<br />
Я глобальная переменная.

Вообще контексты в Blitz - очень мощная штука. С их помощью, по утверждению автора, можно формировать контент любой сложности. Еще бы! Ведь эти контексты могут быть вложенными:

example3.tpl

{{BEGIN root}}<br />
    Я - главный контекст root.<br />
    {{BEGIN child}}<br />
        А я - дочерний контекст child.<br />
        {{BEGIN grandchild}}<br />
            Я - внук #{{$i}} контекста root.<br />
        {{END}}<br />
    {{END}}<br />
{{END}}

example3.php

<?
    header('Content-Type: text/plain');

    $T = new Blitz('example3.tpl');
   
    $T->block('/root');
    $T->block('/root/child');
    $T->block('/root/child/grandchild', Array('i' => 1));
   
    $T->context('/root/child/grandchild');
    $T->iterate();
    $T->set(Array('i' => 2));
   
    echo $T->parse();
?>

Вывод:

Я - главный контекст root.<br />
    А я - дочерний контекст child.<br />
        Я - внук #1 контекста root.<br />
        Я - внук #2 контекста root.

Здесь мы два раза выполняем тело контекста grandchild с разными значениями переменной i. Причем делаем это двумя способами: уже знакомой нам функцией block и вызовами context-iterate-set. Вызов context() устанавливает текущий контекст, над которым будет потом выполнена итерация с помощью iterate() и которому будут присвоены локальные переменные с помощью set().

/root/child/grandchild - это, как Вы уже наверняка догадались, полный путь к контексту. Но можно задавать и относительные пути. Например:

$T->context(‘/root/child’);
$T->context(‘grandchild’);

Это эквивалентно

$T->context(‘/root/child/grandchild’);

Но я бы предпочел использовать более компактный вариант с block().

Для вызова определенного контекста без выполнения всего шаблона можно использовать fetch():

example4.php

<?
    header('Content-Type: text/plain');

    $T = new Blitz('example3.tpl');

    echo $T->fetch('/root/child/grandchild', Array('i' => 1));
?>

Этот пример выведет: Я - внук #1 контекста root.

А что делать, если нам нужно очистить текущий контекст от переменных и/или итераций? Для этого есть функция clean():

example5.php

<?
    header('Content-Type: text/plain');

    $T = new Blitz('example3.tpl');
   
    $T->block('/root/child/grandchild', Array('i' => 1));
   
    echo $T->parse();
   
    $T->clean('/root/child/grandchild');
   
    echo $T->parse();
?>

Этот пример выведет:

Я - главный контекст root.<br />
    А я - дочерний контекст child.<br />
        Я - внук #1 контекста root.<br />
Я - главный контекст root.<br />
    А я - дочерний контекст child.

Но стоит нам убрать вызов clean(), как вывод станет таким:

Я - главный контекст root.<br />
    А я - дочерний контекст child.<br />
        Я - внук #1 контекста root.<br />
Я - главный контекст root.<br />
    А я - дочерний контекст child.<br />
        Я - внук #1 контекста root.

Иногда бывают случаи, когда тело шаблона хранится в переменной (например, если шаблоны хранятся не в текстовых файлах, а в базе данных). Для этого случая есть функция load():

example6.php

<?
header('Content-Type: text/plain');
   
$tpl = <<<TPL
hello, {{ \$world }}!
{{ bye('world') }}
TPL
;

class View extends Blitz {
    function bye($who) {
        return "Bye, $who!";
    }
}

$T = new View();
$T->load($tpl);
echo $T->parse(array('world' => 'world'));
?>

Здесь мы немного расширили класс Blitz и добавили в него свой метод, чтобы потом вызвать из шаблона. Метод, как видите, может принимать параметры прямо из шаблона.

Итоги

В общем, это все основные возможности шаблонизатора Blitz. Официальная документация у него небольшая (как я уже говорил - одна html-страница), ее можно найти здесь (на русском языке). Кстати, если Вы еще туда не заходили, по этой же ссылке приведены результаты тестов, по которым можно более-менее судить о быстродействии этого шаблонизатора. Еще замечание по поводу документации: ее английская версия гораздо актуальнее, поэтому я советовал бы всем обращаться именно к ней.

Теперь мы умеем отделять дизайн от кода, а это очень важно для больших проектов. Но это еще не все. Чтобы практически можно было осуществить это в реальности, я бы воспользовался более старым, медленным, но зато проверенным и мощным шаблонизатором Smarty, о котором расскажу в следущих статьях.

Скачать все примеры к этой статье.





Читайте также:



7 Ответов на “Blitz: шаблонный подход к построению контента”

  1. Интересно было почитать, но чисто познавательно, то, что он работает как модуль начисто, имхо, отбивает все преимущества. Слишком узкая область применения, тем более при разработке для заказчика, а не для своего сервера с рутовым доступом. В общем при написании скриптов на заказ с нуля, имхо, два выбора оправданных шаблонизаторов: Smarty и XSLT, всё остальное от лукавого :)

  2. mif

    Хах, наоборот это один из плюсов, а не минусов. Вы только почитайте, какие у него преимущества в скорости и удобстве использования. А то, что он подключается в качестве модулья, так это не проблема - напишите в тех.поддержку хостинга, и, если он у вас хороший (а для серьезных проектов, особенно для заказчика, по-другому быть не должно), вам его без проблем подключат.
    Не сочтите за рекламу, но, к примеру, на РБК-хостинге это сделали без проблем.

  3. novice

    2 mif: С плохим хостингом это конечно недостаток, но с хорошим - стоит попробовать.

  4. рыбак алексей

    привет, я - автор blitz
    случайно наткнулся на текст, хочу поправить чуть-чуть
    в example2.php нет бага - include “наследует” итерацию, это сделано как раз для больших любителей инклюдов, которым хочется поменьше делать телодвижений - один раз засетил и везде видно.

    касательно ссылок - полезнее давать ссылку на английскую доку, русская устарела, и там не описано очень много. правда, и английская тоже немного устарела 😉

    wbr,
    fisher

  5. novice

    Привет, Алексей! :)
    Исправил статью. Спасибо за комментарий.

  6. Мне не нравится Blitz, хотя работаю на нем уже пол года. Например,
    нельзя сделать так {{ if($a>0,’plus’,’minus’) }}
    нет конструкции {if elseif else}

    Smarty - это хоть не так быстро, но зато гибко и удобно. А скорость для шаблонизатора не самое главное.

  7. Константин

    {{ if($a>0,’plus’,’minus’) }}

    так можно сделать - просто пишете функцию в классе, который расширяет Blitz типа

    function iftype($var_1, $type, $var_2, $comparison_ok=”, $otherwise=”, $eq=”) {
    if ($type=='<‘) {
    if ($var_1 $var_2) return $otherwise; else return $eq;
    }
    elseif ($type==’>’) {
    if ($var_1 > $var_2) return $comparison_ok; else if ($var_1 < $var_2) return $otherwise; else return $eq;
    }
    elseif ($type==’==’) {
    if ($var_1 == $var_2) return $comparison_ok; else return $otherwise;
    }
    }


© Copyright. . I-Novice. All Rights Reserved. Terms | Site Map