Шаблонизатор своими руками

MasterSID

Новичок
Шаблонизатор своими руками

Продолжая тему написания собственного шаблонизатора.

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

Первые пишутся на основе классов и используют некий централизованный буфер для накопления всех данных, которые нужно подставить в шаблон, и по команде парсят их. Например:
$template->assignvar("VAR", "VALUE");
$template->display();

Вторые работают без парсера. Они собирают все данные в необходимые переменные, а в самом шаблоне используются непосредственные конструкции вывода содержимого этих переменных, типа <?=$var?>

Безспорно, что вторые будут работать гораздо быстрее первых, будут иметь возможность использовать тот же PHP. Возможно есть еще много плюсов, но все ли так хорошо, как кажется?

Хотелось бы услышать ваши аргументы в пользу каждого из этих способов. Кто как думает?

P.S. Кстати, есть еще один интересный тип, который является толи вариацией второго, толи чем-то отдельным - он использет в шаблоне функции, подставляющие в определенные места нужные значения. Вроде этого: <?=getContent()?> Мне кажется что такой подход не гибок и не удобен, т.к. иногда может потребоваться обработать такую ситуацию, когда этого контента нет и нужно заменить теги, окружаюжие данную конструкцию, а если возложить весь вывод этого блока на такую функцию, то можно растерять описание всего оформления.
 

alexhemp

Новичок
MasterSID

На мой взгляд классификация у тебя верная, только вот на деле - признаки - независимые :)

Единый класс для шаблонизатора не означает что нельзя для вывода использовать штатный php - пример - Savant2

Итак, рассмотрим первый признак - использование класса, как промежуточного буфера.

Плюсы:
1. Не захламляется GLOBALS - отсюда лучше контроль за данными
2. Инкапсуляция - можно добавить не только "буфер" но и методы работы с ним - например - очистить одной командой - или получить назад переменную и т.п.

Минусы:
Очевидно лишний код, который каждый раз компилируется, это плата за удобства объектно-ориентированного синтаксиса (в самом деле, если нет нормального дерева объектов, то от ООП остается только инкапсуляция и удобный синтаксис).

С ним можно бороться установкой php-акселлератора, который кэширует байт-код php-скриптов, и позволяет не компилировать их при каждом старте, а только один раз - при изменении.

И второй признак - использование собственного языка шаблонов супротив php-вставок

Сразу предупрежу - тут - вкусовщина

Плюсы:
1. Для простых случаев более простой синтаксис шаблона, "понятный" HTML-верстальщику
2. Выше контроль за кодом шаблона, нельзя использовать произвольный php-код, что затрудняет проникновение бизнес-логики в шаблон.

Минусы:
1. Необходимость парсинга шаблона
2. Все-таки свой, нестандартный синтаксис шаблона

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

Лисю

Guest
MasterSID
Можно так же прочесть: http://phpclub.ru/talk/showthread.php?s=&threadid=70870&rand=64

Вкратце, там обсуждается такая проблема: нужно вывести на кнопочке текст. При условии, если режим редактирования, то надпись должна быть "Edit". Иначе - добавление записи - "Add". А ещё, возможно, придётся выводить надпись или на русском или на китайском языках. Т.е. многоязычный интерфейс.

Обсуждается, какой сценарий должен определять какую именно надпись выводить - программа или шаблон. Единодушно, пришли к мнению, что-либо контроллер шаблона (если таковой имеетца) или непосредственно шаблон. Т.е. в самом коде, который "собирает все данные в необходимые переменные" лучше не держать значения "Edit/Изменить" и "Add/Добавить", а выносит их куда-нибудь в конфиг или на крайняк держать в самом шаблоне.

так

<!-- BEGIN 1 --!><font color='red'>{user_name}</font><!-- END 1 --!>

<!-- BEGIN 2 --!>{user_name}<!-- END 2 --!>
если это "крутой" шаблонизатор типа без логики представления (хотя эта логика на лицо)

или, например, так

PHP:
<? if(...): ?>
   <font color='red'>{user_name}</font>
<? else: ?>
{user_name}
<? endif; ?>
нужно ПРАВИЛЬНО строить шаблон. С условием (логикой) (а ещё понадобятся потом циклы, вложенные if-else конструкции).

Теперь подумай, сможешь ли ты качественно реализовать шаблонизатор, который будет делать почти то же, что и делает PHP во 2 методе.
Есл нет - используй 2 метод.

-~{}~ 29.08.05 15:55:

Вот, посмотри, как я делаю.
Сценарий гостеавой книги.
Подшаблон, инклюдищийся в ОСНОВНОЙ шаблон: http://m17.spaceweb.ru/~airstuda/gb__index.php.txt
Переменная $html__gb определяет, какой именно инклюдить шаблон - для зарегестрированных или не для зарегестрированных пользователей.

Подшаблон, инклюдищийся в шаблон см. выше: http://m17.spaceweb.ru/~airstuda/gb__user_in.php.txt
 

Valentin

Новичок
У меня так... Есть класс CTemplate

CTemplate::assign($name,$value) - переносим необходимые переменные, которые используются в php-коде. Переносим их в html шаблоны. В html они типа <?=$name?>

CTemplate::m_page - путь к суппер-шаблону, который подключает шаблоны: CTemplate::m_blocks[] - путь к шаблонам-блокам.

В CTemplate::m_page шаблоне:
1-открываются все шаблоны m_blocks[]
2-и ещё дополнительные команды <?include(...)?>

Ну и логический конец - это ...

require(CTemplate::m_page);
ob_start();
$content = ob_get_contents();
ob_end_clean();

echo $content;

Как видите, изначально шаблонизатор очень простой... При грамотном проектировании, присутствие в html шаблонах php-кода можно снизить до уровня <?=$name?> и <?include(...)?>, ну и ещё разных операторов <?foreach(...){...}?> <?for(...)?> можно и <?if(...)?>. Короче структурные операторы я очень редко, но допускаю в html.

Пока такая схема меня устраивает, а псевдо-php-код, типа Smarty, я сочинять не собираюсь. Кстати и на скорость выполнения не жалуюсь.

Короче, разделяйте и властвуйте, и следуйте от общего к частному :)) и ещё абстрагируйтесь и инкапсулируйтесь :)) тогда даже самый простой шаблонизатор будет вполне вас устраивать :))
 

MasterSID

Новичок
И второй признак - использование собственного языка шаблонов супротив php-вставок
Мне кажется, что это лишняя работа и неоправданная нагрузка на сервер. Второй вариант шаблонизатора, описанный мною ИМХО более разумное решение, чем написание собственного интерпритатора на php. Если я не прав, то с удовольствием выслушаю противоположную точку зрения. Тогда вопрос будет стоять так: php vs own_interpritator - какие реальные преимущества дает каждый.

А вообще, даже при использовании акселератора один из вариантов все равно останется выйгрышным. Так не лучше ли использовать его (при условии, что второй не даст реального функционального преимущества - что я и хочу узнать). Я, конечно, не маньячу до такой степени, что долой ООП, даешь голый код и скорость, просто думаю нужно найти компромис. А вообще, мне каца, под разные проекты подойдет свой тип шаблонизатора.

Теперь подумай, сможешь ли ты качественно реализовать шаблонизатор, который будет делать почти то же, что и делает PHP во 2 методе.
Лисю - я пока что за 2ой вариант - ты меня им заинтересовал, просто может кто-то сможет меня перубедить? :)

Valentin, не мог ты привести код своего шаблонизатора целиком. Мне интересно.

-~{}~ 29.08.05 17:19:

Кстати, если кому-то важно, то
{
echo get_file_contents("sid.psd");
}
VS
{
ob_start();
include $file;
$content=ob_get_contents();
ob_end_clean();
echo $content;
}

по скорости с соотношением 20% - 80% затрат времени побеждает первый вариант. Правда не убъет ли это преимущество self-made парсер? Проверю в слеюдующем тесте.
 

alexhemp

Новичок
MasterSID

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

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

В моем производственном цикле это происходит так

1. Я пишу административную часть сайта, она как правило значительно сложнее самого сайта (ну что поделать, заказчики у меня такие)
2. Дизайнер ваяет нетленный дизайн
3. Я пишу сам сайт, общение с административной частью - только через БД, части полностью независимы, могут работать на разных серверах и устроены совершенно по разному
4. Верстальщик верстает, снабжая код комментариями (если повезет)
5. Я режу сверстанные куски на шаблоны, вставляя где надо все подстановки, делая логику (типа цветов строк таблицы и т.п.)
6. Все мы это тестируем и сдаем.

Теперь если заказчик решил поменять какой-нить шаблон, дизайнер рисует что-то новое, верстальщик верстает, а потом меняет шаблон, по образу и подобию. За пару лет работы они меня звали пару раз, когда сильно менялась логика сложного шаблона, но 90% изменений логику вообще не трогают, ну и плюс ее не так много как может показаться.

Раньше мы работали с собственным шаблонизатором, и много мучались например с логикой показа блоков.
Теперь в коде определяется - максимум имя шаблона, типа "order.cart.tpl" или "order.ok.tpl" причем имя шаблона строиться как можно заметить из "модуль.действие.tpl" ;-)
 

Popoff

popoff.donetsk.ua
Вторые работают без парсера. Они собирают все данные в необходимые переменные, а в самом шаблоне используются непосредственные конструкции вывода содержимого этих переменных, типа <?=$var?>
В моем шаблонизаторе есть парсер. Он генерирует php-файл на основании xml-файла. Если я не ошибаюсь, примерно по такой схеме работают большинство современных шаблонизаторов, в том числе и смарти.
Итак, рассмотрим первый признак - использование класса, как промежуточного буфера.

Плюсы:
1. Не захламляется GLOBALS - отсюда лучше контроль за данными
У меня глобальные переменные тоже не используются. В xml-документе для каждой переменной можно указывать область видимости. И даже если она указана глобальной, эта переменная глобальна с точки зрения шаблона, а с точки зрения кода на php это - локальная переменная. И даже не переменная, а индекс в массиве.

Это я к тому, что незахламляемость глобалсов - это не особенность использования классов, ее можно получить и при использовании других способов.
И второй признак - использование собственного языка шаблонов супротив php-вставок

Сразу предупрежу - тут - вкусовщина

Плюсы:
1. Для простых случаев более простой синтаксис шаблона, "понятный" HTML-верстальщику
2. Выше контроль за кодом шаблона, нельзя использовать произвольный php-код, что затрудняет проникновение бизнес-логики в шаблон.

Минусы:
1. Необходимость парсинга шаблона
2. Все-таки свой, нестандартный синтаксис шаблона

Основной минус - замедление работы, с ним и будем бороться ;-)
Очевидно, что шаблон нужно компилировать в php-код (просто тупо вместо выполнения кода - записываем его в файл), который потом будет кэширован акселератором.
2. Мне кажется, что стандартного синтаксиса в шаблонах такого типа нет и быть не может. Какой синтаксис не возьми - он стандартный только в некоторых шаблонах, а в других шаблонах стандартным будет другой синтаксис. На то это и "собственный синтаксис".

3. Никакого замедления работы нет. Парсим - генерируем php-код - подключаем его обычным include. Дольше будет только при первой загрузке шаблона.

-~{}~ 29.08.05 18:17:

[offtop]

причем имя шаблона строиться как можно заметить из "модуль.действие.tpl" ;-)
А я для всех имен в своем проекте использую иерархическую организацию имен:
http://popoff.donetsk.ua/text/work/prg/naming/

Если применить к твоей фразе, то используя иерархическую организацию имен, "действия" можно разбить на категории.

[/offtop]
 

alexhemp

Новичок
Popoff

Говоря "нестандартный" я имел ввиду "отличный от php-вставок" :) Безусловно, стандартного нет, тут уж как получиться.

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

Ну и потом, я стараюсь не делать пары шаблонов "верх"-"низ" а использовать вложения шаблонов - в целом их не больше 50 выходит на проект :)

-~{}~ 29.08.05 21:30:

а про незахламленность глобалсов - ясное дело, что это можно получить по другому, но в самом простом варианте, когда сперва

file.php:

$somevar='xxx';
include ('file.html');

file.html

<h1><?=$somevar?></h1>

Как раз захламляются глобальные :) Мне кажется проще ассигнить переменные с помощью методов класса, отлаживать удобнее - dump_var($template_object) и все ;-)

Насчет иерархий областей видимости - это конечно круто ;-) Даже не представлю где такое может понадобиться...

Но на практике редко встречается злонамеренный верстальщик, поэтому достаточно 2-х уровней - "скрипт" и "шаблон", которые как раз такой передачей и реализуются.
 

master_x

Pitavale XXI wieku
интересная дискуссия, только все же зачем нужен собственный шаблонизатор? Я всегда был за то, чтобы использовать в шаблонах чистый PHP, т.к. этот вариант всегда работает быстрее всех. Да и не слишком он сложный, синтаксис отдельных шаблонизаторов бывает сложнее. Насчет работы с XML- это вообще томоз. Можно хранить данные в том формате, который быстрее всего обрабатывается, а если надо конвертить его в XML. Вообще, все выше сказанное относится только к серъезным приложениям, у которых скорость- критический параметр.
В конце концов не забывайте старую истину- PHP-сам по себе самый обыкновенный шаблонизатор.
 

MasterSID

Новичок
Может кто-то скажет что я не прав, но такой подход, master_x я бы тоже назвал шаблонизатором. По крайней мере в моем понимании шаблонизатор отделяет представление от бизнес-логики, используя заранее предопределенные шаблоны представления. Вот я и выбираю между двумя типами. Пока что склоняюсь к использованию самого PHP внутри шаблона и серъезных доводов против этого метода еще не увидел.
Захламление глобалсов имхо не серъезно - и реальной угрозы гибкости не несет. В чем еще второй метод может проиграть в гибкости?
Если кто-то не понял о чем я говорю:
Второй метод работает так:
Шаблон:
<html>
<head><title><?=$TITLE?></title></head>
<body><?=$BODY?></body>
</html>

Шблонизатор:
$TITLE='TITLE';
$BODY = get_file_contents($file);
 

alexhemp

Новичок
MasterSID

Я пытаюсь сказать - что рассматривать шаблонизатор в отрыве от задачи - глупо.

Для маленького сайта с одним программистом безусловно не нужно ничего изобретать, достаточно правильно использовать PHP.

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

Я вот лично люблю смарти - за модификаторы. :) Они реально сокращают код.
 

MasterSID

Новичок
Похоже мы друг друга не поняли. Ставя вопрос первый метод vs второй, я фактически ставлю вопрос smarty vs php и хочу узнать какой метод окажется наиболее удобным и полезным
 

crocodile2u

http://vbolshov.org.ru
Дело вкуса, имхо. Лично мне смарти в общем и целом нравится, использование кода пхп в шаблонах не нравится (см. топик о Savant http://phpclub.ru/talk/showthread.php?s=&threadid=70844).

"Тормоза", которым подвержен смарти - насколько мне известно, не более чем миф.

ЗЫ: в приведенном примере:
PHP:
<h1><?=$somevar?></h1>
Разработчик полагается на short_open_tags = On. Да, в подавляющем большинстве случаев это позволительно. Но все же нехорошо.
 

MasterSID

Новичок
миф??? создай два проекта, которые делают одно и тоже, только первый через смарти, а второй через php и померь скорости выполнения и сравни в процентах.
 

crocodile2u

http://vbolshov.org.ru
Миф, миф... :)
Суть даже не в отличии в скорости выполнения, а в том, что смарти не является "узким местом" с точки зрения производительности (оговорюсь - очевидно, в большинстве, но не в любых проектах), и эти отличия не настолько велики, чтобы отпугивать.
 

MasterSID

Новичок
невелики они для слабо нагруженного сервера, а когда проект реально серъезный все выльется в деньги
 
Сверху