Pull to refresh

Вся правда о шаблонизаторах

Reading time10 min
Views35K
Статейка старенькая, но думаю до сих пор актуальная

Cлишком часто я в последнее время слышу слово «шаблонизатор». Не утихают споры между сторонниками разных шаблонных движков. Одни говорят что логика в шаблонах это хорошо, другие считают что это зло. Даже сейчас очень часто встречаются проекты, написанные вообще без применения какого либо шаблонизатора. Но в этой статье я не буду предпринимать попыток стать на сторону одной из сторон. Я не буду вам доказывать преимущества ни одного из подходов. Я просто постараюсь рассказать обо всех из них с точки зрения теории. Эта статья не о конкретных программных продуктах, а о способах выделения логики представления в ваших приложениях.

Термины

В статье используется ряд терминов, которые могут быть вам неизвестны. Попробую дать определение некоторым из них.

Представление – логика приложения отвечающая за отображение данных. Для WEB приложений это та логика которая формирует HTML страницу.
Домен – Часть приложения отвечающая за обработку данных, то есть содержащая бизнес-логику приложения. Выражения «бизнес-логика» и «логика домена», по сути синонимы.
Шаблон – Файл, содержащий HTML и некоторые маркеры, позволяющий этот шаблон обработать и сформировать на его основе конечный HTML код.
Шаблонизатор – приложение, осуществляющее обработку шаблона.
Паттерн, Типовое решение – решение часто встречающихся задач.

Шаблонизатор как миф

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

Дело в том, что слово «шаблонизатор» часто считают синонимом слова «представление». Заочно считается, что если вы в своих проектах применяете шаблонизатор, то вы отделяете логику представления от бизнес-логики. Некоторые даже думают что шаблонизаторы созданы для дизайнеров/верстальщиков, а программисту они не нужны. Так вот, все это миф. Шаблонизатор это программа созданная для того, что бы сделать разделение логик удобнее, предоставляющая некоторые расширенные функции, но она никак не является камнем преткновения. Вы можете использовать любой шаблонизатор или можете вообще обойтись без него, но при этом хорошо выделять представление из вашего приложения. И наоборот, вы можете использовать Smarty, но при этом окончательно все запутать, и переплести. Поэтому говоря что вы используете конкретный шаблонизатор, вы лишь доносите до сведенья тот факт, что вы пользуетесь неким программным продуктом, но это совершенно не говорит о том как хорошо написано ваше приложение.

Разделение HTML и PHP

С этого все началось. Любой из вас помнит те незапамятные времена, когда все вокруг восторгались возможностью PHP проникать в код HTML, становясь его частью. Благодаря этому значительно упрощалось понимание языка. Многим даже казалось что HTML и PHP братья, работающие сообща, рука об руку(многие до сих пор в этом уверены). Даже те кто понимал что PHP на самом деле ничего не знает о HTML(как впрочем и HTML о PHP), и лишь выводит текст, были рады тому что не приходится писать кучу print. Все так просто!
И эта простота породила проблему.

Борщ

Борщ только на первый взгляд кажется хаосом. На самом деле, хорошо приготовленный борщ — он вкусный. Но если вы добавите туда немного больше капусты, больше соли и мало воды… Будет невкусно. В борще главное не переборщить (извините за каламбур).
Собственно, никто не хотел зла. Просто новый язык привлек конечно и новых программистов. Именно новых, польстившихся на простоту PHP, удобство и мощь. Мы тогда не знали ни о каких MVC. Мы не задумывались над проблемами сопровождения кода, читабельности и стабильности. Оно работало, и мы искренне радовались этому.
Но скоро мы поняли что борщ становится невкусным. Складные сначала чередования PHP и HTML становились слишком сложными для восприятия. Смена дизайна вообще превращалась в кошмар. Мысли о том что мы уже это когда-то писали становились навязчивыми, но место где этот код уже был написан, найти было крайне сложно. Еще сложнее было вытащить его оттуда и вставить в новый проект.
Но хватит лирики. Разными путями мы пришли к пониманию что нужно код HTML отделить от PHP кода. И вот тут мы узнали слово «шаблонизатор».

Что такое шаблонизатор?

Это программа, призванная отделить PHP код от HTML кода. Бытует мнение это нужно для дизайнеров. На самом деле мне ни разу не приходилось сталкиваться с дизайнерами (извините верстальщиками), которые бы верстали сразу шаблоны. Но дело не в этом. На самом деле плевать хотели программисты на верстальщиков. Им самим уже надоело удовлетворять новые изыски дизайнеров, перелопачивая при этом весь код.
К этому моменту программиста уже тошнило от всякого кода, перемешенного с PHP. По крайней мере я напрочь отрекся от любого вида логики в HTML. Мой шаблонизатор мог повторять куски кода (блоки), включать другие файлы, но ни о какой логике речи быть не могло. Я потратил целые выходные на написание своего шаблонизатора. Я был горд, и считал себя самым правильным программистом. Но вскоре проекты усложнились. И даже при всей мощи моего шаблонизатора, HTML все равно просачивался всякими путями в мои проекты.

Бизнес-логика и логика представления

Наконец мы приближаемся к сути. На самом деле, выделяя логику из HTML кода, мы немного переборщили. Пытаясь писать правильно, что похвально, программисты взяли курс на полное отделение PHP от HTML. Как будто в мире только эти 2 языка и существуют. А вот на самом деле PHP и HTML это всего лишь инструменты. Причем инструменты взаимодополняющие друг друга. Вы наверное не будете спорить что HTML определяет вид вашего сайта. А PHP занимается тем что формирует этот вид на основе данных. Но можно ли четко разделить PHP и HTML? Да нет конечно! PHP все равно определяет как будет выглядеть ваша страница[[*1]]. Получается что HTML это только представление, а PHP занимается не только получением данных но и определяет как, где и сколько, их показать. Возвращаемся к тому от чего ушли. Оказывается отделить PHP от HTML невозможно? Я скажу больше. И не нужно!
На самом деле вопрос не в том отделять ли PHP от HTML, а в том где их разделять.

Логика представления

Логику любой программы можно разделить на две составляющих – логику, которая получает и обрабатывает данные[[*2]] и логику которая их показывает пользователю. Первая называется бизнес-логикой а вторая логикой представления. Важно уметь четко разделять эти 2 вида логик, так что бы они не перемешивались. Применительно к web-программированию можно с абсолютной уверенностью говорить что HTML относится к логике представления а база данных это вотчия бизнес-логики. Но между ними есть еще масса PHP кода. Сложность в том, что бы разделить этот код. Наконец мы пришли к той проблеме которая меня побудила написать эту статью. На самом деле давно существует стереотип который утверждает что PHP никак не может быть частью логики отображения. Этот стереотип появился неспроста. Вспомните, что когда-то мы мешали код PHP и HTML. Потом мы узнали, что так делать не следует, а следует пользоваться шаблонизаторами. С этого момента мы подсознательно проводим четкую границу между PHP и HTML, стараясь их никогда не смешивать. Я не пытаюсь сейчас утверждать, что нужно смешивать. Но нужно понимать что PHP так же отвечает за то как будут показаны данные, то есть имеет непосредственное отношение к логике представления. Важно понимать что вопрос перемешивать ли код PHP и HTML или не перемешивать не имеет никакого отношения к разделению двух логик. Можно перемешивать а можно и четко отделять, и при этом говорить, что в программе эти логики хорошо разделены. Понимание этого является очень важным. Если вы четко разделяете PHP и логику представление то вы глубоко заблуждаетесь. Например Smarty самый популярный из шаблонизаторов не использует в своих шаблонах PHP в чистом виде. Но тем не менее он компилирует свои шаблоны и в итоге получается именно смесь PHP и HTML.

Два типа представления

Спор о том применять ли логику в шаблонах или нет вечен. Ибо даже у Мартина Фаулера говорится о двух типах слоя представления: представление по шаблону и представление с преобразованием[[*3]].

Представление по шаблону (Template View)

Как пример, всем известный Smarty. В шаблоны Smarty передаются данные, и уже сам шаблон определяет как эти данные показать. Но представьте себе что эта возможность уже встроена в PHP! На самом деле скажите мне чем PHP отличается от шаблона Smarty? Чем теги Smarty ({}) не похожи на теги PHP ()? Да, в сущности, одно и тоже! Помните как более опытные коллеги говорили вам что мешать код PHP и HTML нехорошо? Так вот, вас обманули[[*4]]. Возможно те, кто вам об этом рассказал и сами не понимали что код PHP и код Smarty близнецы-братья, возможно вас просто предостерегли от больших ошибок.

PHP vs. Smarty

На самом деле PHP в руках неопытного программиста действительно становится неуправляем. Вспомните про борщ. Если не уметь его готовить то он становится невкусным. PHP позволяет слишком многое, и по неопытности может возникнуть соблазн напихать в PHP шаблоны различной логики не присущей представлению. Например, никто не помешает вам выполнять в коде SQL запросы. Smarty, в этом отношении безопаснее. Конечно и в Smarty можно, умеючи, все испортить. Например, написать функцию выполняющую SQL запросы[[*5]]. Но все таки для этого нужно приложить гораздо больше усилий.
Вторым доводом против PHP шаблонов может быть синтаксис. Мы уже договорились не рассматривать тут проблемы верстальщиков. На сам деле {$var} читается лучше чем или, что более правильно,.
Еще одна проблема, это отсутствие кэширования. Но это довод только для проектов с высокой нагрузкой. Конечно, в этом случае проще использовать уже готовый Smarty, чем изобретать что-то свое.

Все что я сказал выше не направленно на то, что бы вы бросали Smarty и срочно переходили на plain PHP. Просто вы должны четко понимать что код в HTML не значит плохо. Если его использовать правильно, в нужных пропорциях, то ничего страшного в этом нет. Это всего лишь один из способов разделить приложение на слои, и отделить слой представления от остальных. Я сам использую Smarty, потому что мне так удобно. Но я прекрасно понимаю что Smarty это всего лишь удобная прослойка, которую, при необходимости, можно убрать.

Пример

Самый простой способ передать переменные в шаблон PHP, просто объявить их, перед включением шаблона в код.

$var = 'Hello, world!'
include 'template.php';


Но такой способ имеет ряд неудобств. Во-первых, такая передача переменных непрозрачна (иногда сложно найти место, где переменная была объявлена).
Во-вторых, если переменная не объявлена, но она используется в шаблоне, PHP выдаст ошибку уровня Notice, а это не всегда удобно (например Smarty нотисов не выдает). В-третьих, те, кто использовал Smarty, привыкли работать с объектом, используя привычные методы Assign и Fetch. Все эти недостатки легко обойти.

Посмотрите на нижеприведенный код и сравните его с кодом смарти. Конечно здесь не реализованы все методы класса Smarty, но дело не в этом. Дело в том что 90% требуемого функционала Smarty реализовано в двух десятках строчек кода. Шаблонизатор в 20 строк! Не считая кода самого PHP :)

class PlainPHPView {
public $template_dir = TEMPLATES_DIR;
protected $Vars = array();

public function __construct($template_dir = '') {
$this->template_dir = $template_dir ? $template_dir : $this->template_dir;
}

public function Assign($var_name, $var_value) {
$this->Vars[$var_name] = $var_value;
}

public function Fetch($template) {
$reporting = error_reporting(E_ALL & ~E_NOTICE);
extract($this->Vars);
ob_start();
include $this->template_dir.'/'.$template;
ini_set('error_reporting', $reporting);
return ob_get_clean();
}

public function get_template_vars($var) {

return isset($this->Vars[$var]) ? $this->Vars[$var] : false;
}
}


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

$var = 'Hello, world!'
$view = new PlainPHPView('./');
$view->Assign('var', $var);
print $view->Fetch('template.php');


Представление с преобразованием (Transform View)

Помимо спора мешать ли PHP и HTML или использовать Smarty, существует еще не менее принципиальный, но и не менее бесполезный спор. Спор о том помещать ли вообще какую бы то нибыло логику в шаблоны.

В шаблонах на основе паттерна «Представление с преобразованием» нет явной логики[[*6]]. Это практически чистый HTML. Но перед выводом этот HTML, преобразовывается с помощью некоторой логики, и только после этого отдается клиенту. То есть представление определяется не только самим шаблоном, но и специальным кодом, этот шаблон обрабатывающим. Мартин Фаулер приводит в качестве примера XSLT преобразование XML данных. Я же хочу привести пример более приближенный к реальности: FastTemplate.
В шаблонизаторах подобных FastTemplate логику определяет код. Сам шаблон содержит лишь HTML и специальные маркеры, которые отмечают участки шаблона, которые необходимо обработать. Сам «преобразователь» читает шаблон, и преобразует его в конечный HTML.
При этом, в сложных шаблонах, очень сложно избежать полного отделения PHP от HTML. Все таки, например, код ссылок, или элементы форм проще формировать в самом скрипте-преобразователе. И это не является плохим решением. На самом деле и шаблон, и «преобразователь» работают сообща и вместе находятся в слое представления. Но при использовании этого паттерна еще важнее суметь правильно разделить слои, так что бы они не перемешивались. Например, неплохо бы «преобразователь» оформить в качестве класса, тем самым абстрагировав его от остального кода.

Помошники (Helpers)

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

Например, формирование ссылки, или элементов форм. В любом случае, удобнее всего этот код вынести из шаблона и оформить в виде функции или класса, или его метода. Как пример — система плагинов Smarty. Такие функции называются «помощники» или Helpers. В самом деле, попробуйте написать код в шаблоне, формирующий календарь. Уврен у вас это получится. Но если календарь потребуется в другом шаблоне, или даже проекте? Copy+Paste конечно выход, но не решение. Гораздо проще оформить такой код в виде метода класса. Конечно это усложнит смену дизайна, ведь теперь вид вашего сайта зависит не только от шаблона. Но не стоит забывать, что представление, это не только шаблон, а весь набор классов и функций, лежащих в слое представления.

Так что же такое шаблонизатор?

Как я сказал шаблонизатор это миф. Миф не сам по себе. Мифом он является в контексте, в котором это слово частенько применяют. Наверное вас спрашивали на собеседовании, перед приемом на работу, о том каким шаблонизатором вы пользуетесь. Ответ «никаким» сильно понижает ваши шансы быть принятым на работу. На самом деле работодатель имел виду несколько иное. Он хотел вас спросить каким образом, а не с помощью чего, вы разделяете логику приложения на слои. Но в представлении многих, к сожалению, шаблонизатор и логика представления это слова — синонимы, если конечно последний термин вообще известен вашему собеседнику. Попробуйте ответить что вы не пользуетесь шаблонизаторами, а используете смесь PHP и HTML. 5 к 1 что вас не возьмут :)

Вывод

Помните как кто -то мудрый заметил что история имеет тенденцию двигаться по спирали, часто повторяясь, но на более высоком уровне? Кода-то мы перемешивали код PHP и HTML, потом узнали что это плохо, а теперь оказывается что не так уж и плохо. Когда то я сам считал что логика в шаблонах это зло, а теперь пишу статью о том что это всего лишь одни из подходов.
В этой статье я не проследовал цели изменить ваши взгляды. Если вам нравится Smarty, не стоит от него отказываться. Если вы обожаете FastTemplate и ему подобные движки, это тоже ваше право. В каждом выборе есть свои плюсы и минусы. Главное что бы выбор решения был на основе четких критериев и полного осознания их веса в широком выборе имеющихся вариантов. Руководствуясь навязанными стереотипами, вы сами лишаете себя права такого выбора. Надеюсь эта статья заставит вас шире взглянуть на проблемы, с которыми вы сталкиваетесь в нелегком деле создания web-систем.

— [[#1]] Например, сколько раз показать тот или иной блок, вывести текст в 2 колонки, вывести таблицу, в которой строки имеют разный цвет… обычным HTML добиться таких эффектов будет сложно.

[[#2]] Приложение обычно делятся на 3 слоя, но в этой статье мы будем делить приложение на 2 слоя, логику представления и все остальное.

[[#3]] У Фаулера говорится о трех типовых решениях, но третий является объединением первых двух. Для буквоедов поясню что Smarty как раз и относится к третьему виду, объединяя в себе типовые решения «Представление по шаблону» и «Представление с преобразованием».

[[#4]] Smarty именно этим и занимается, компилируя свои шаблоны именно в смесь PHP и HTML кода.

[[#5]] Кстати не дай бог мне навязать вам еще один стереотип. Слой представления вполне может самостоятельно выбирать данные из БД, в обход слоя бизнес-логики, и даже самостоятельно передать эти данные, например для сложных вычислений, в слой домена. Такие шаблоны еще называют активными. Не решение определяет архитектуру, а архитектура требует решений :)

[[#6]] Логика все же есть. Но это неявная логика. community.livejournal.com/ru_php/789059.html

**Диаграммы взяты с сайта Мартина Фаулера** www.martinfowler.com
Tags:
Hubs:
Total votes 18: ↑9 and ↓90
Comments48

Articles