Pull to refresh

Comments 71

Я со Smarty почти не работал, но одно могу сказать точно: в Smarty логика и представление слишком связаны, что очень сильно мешает. Хорошо, если вы сами занимались разработкой проекта, но стороннему разработчику довольно сложно в эту мешанину вникнуть сходу.
Каким образом связана логика с представлением в смарти? Если Вы реализовываете логику на смарти это не значит, что смарти плох.
А по поводу безопасности так если вы используете native php — какая безопасность если можно вызвать всё? в смарти есть только определенный набор разрешенных функций которые можно вызывать. т.е. по сути можно сделать что бы клиенты вашего сервиса правили свои шаблоны и это будет безопасно в отличии от native php.
ЗЫ. для рекурсий есть {function}
Если Вы реализовываете логику на смарти это не значит, что смарти плох.
Так я же написал
но стороннему разработчику довольно сложно в эту мешанину вникнуть сходу.

Приходилось дорабатывать проект с такой кашей. Хотя, это скорее проблема того разработчика, а не Smarty.
Сложный шаблон на чистом PHP производит намного более удручающее впечатление…
Запись без шаблона — <? if (isset($item['key']):?> <?= $item['key'] ?> <? else: ?> default <?endif ?>
тоже самое в смарти — {$item.key | default:'default'}
Я на чистом php стараюсь не писать, как правило использую фреймворки вроде Zend, где всё довольно красиво.
Там подобное в помощниках вида или в контроллере, а не всё в куче.
То есть, что бы написать один if нужно вызвать четыре класса и сделать пару записей в сингелтон?
Вы специально всё утрируете?

Если у вас всего один if и выводится одна переменная, то вам шаблонизаторы вообще не нужны.
да, нет… просто много поработал над крупными проектами… в которых в шаблонах было такое, разбираться в чем врагу не пожелаешь… А начиналось все невинно с небольшого кода… Проект растет и развивается, и через некоторое время смарти начинает выигрывать и по чисто те кода и по его понятности для того кто поддерживает…
А почему не так?
<?=isset($item['key']) ? $item['key'] : 'default'?>

А если говорить не о наличии индекса в массиве, а о ненулевом значении, то ещё проще (PHP 5.3)
<?=$item ?: 'default'?>
А почему не так?
<?=isset($item['key']) ? $item['key'] : 'default'?>

Пример взят из реального проекта и там между ?> и <? еще что то HTMLное вставлено… поэтому так как я записал!

А если говорить не о наличии индекса в массиве, а о ненулевом значении, то ещё проще (PHP 5.3)
<?=$item ?: 'default'?>

Эх…
Пример взят из реального проекта — И там нужно было выводить элемент массива и проверять его на существование. и при отсутствии вывести значение по умолчанию…
Вы задачу то не подгоняйте, под любимый метод решения, не подгоняйте, плохая это практика!
Разве я подгоняю? Как раз наоборот, этим занимаетесь вы.
Запись без шаблона — <? if (isset($item['key']):?> <?= $item['key'] ?> <? else: ?> default <?endif ?>
тоже самое в смарти — {$item.key | default:'default'}

Почему-то в примере на PHP у вас между ?> и <? еще что то HTMLное, а в примере на смарти ничего.
Ок значит вру…
Вы все свои проекты трехлетней давности помните?
Код для примера выдернул из письма по проекту… Если упереться то я думаю я найду и шаблон в архивах и причину почему там столько угловых скобок… Если оно конечно мне станет надо))))
Да что ж вы так злостно реагируете?
Я прекрасно представляю, как может выглядеть код с шаблонизатором и без него.

Если вы обратите внимание, я прокомментировал ваш конкретный пример, а не целесообразность использования смарти вообще. Если в вашем примере между ?> и <? должно быть что-то ещё, то исключительно ради честности следовало бы привести аналогичный пример на смарти:
{if $item.key} {$item.key} {else} default {/if}

Вообще я предлагаю не становиться заложником инструмента, а понимать насколько он уместен в каждом конкретном случае.
isset это не проверка на ненулевое значение. Прежде всего это проверка на то, что переменная вообще существует, без появления нотайса, если не существует. В вашем примере получим нотайс «Undefined variable», если переменная не определена. Вообще из-за этого конструкция $var ?: 'default' бесполезна практически :(
Где-то в доках смарти было написано: наиболее частой ошибкой начинающих разработчиков является смешивание логики и представления.
Вообще-то PHP был когда то написан как язык шаблонов для perl…

То есть писать шаблоны на PHP вполне логично. Но потом он развился… и теперь можно сделать на нём слишком много. И это есть причина почему настоящие собаководы рекомендуют использовать шаблонизаторы. А между строк читаем — «шаблоны предназначены для того, чтобы сузить функциональность, и защитится от криворуких верстальщиков, которые пишут спагетти-г… код»
Где то мне попадались тесты, код скомпилированный смарти иногда обгоняет код написанный руками по быстродействию, из за использования более быстрых конструкций языка, или как минимум не отстает.
А жуткая мешанина php лапши в шаблонах зачастую мешает читать шаблон, да и постоянно кто то из «молодых» пытается вынести все в шаблон вплоть до запросов к базе данных, вычесывание такого кода. замедляет общий процесс разработки.
Строка из статьи:
echo '<option ...>'.$node['name'].'</option>';

Как можно ускорить эту строку… в несколько раз?)))) А заодно и сильно уменьшить потребление памяти в операции?
Не нашел где это. Но собственно ссылку привел для того что бы показать что native php будет быстрее.
Но при использовании кеша в смарти есть вероятность что смарти будет быстрее. (если к примеру в шаблоне будут какие нибудь вычисления :) )
Ну собственно я и про это кстати тоже))))
echo '<option ...>', $node['name'], '</option>';
Верно)))) Только вот в реальном проекте у любителей «шаблонов на чистом php» я за десять лет такую запись встречал ОДИН раз… Все через точку стараются сделать… а не через запятую…
Вы опять лукавите. Откуда возьмётся «в несколько раз»?

Проведите эксперимент:
$start = microtime(1);
ob_start();
for($i=0; $i<1000000; $i++) echo 'a' , $start , 'b';
ob_end_clean();
die(microtime(1) - $start);

У меня получились такие результаты:
точка — 0.99 сек
запятая — 0.91 сек
«a{$start}b» — 1.0 сек
sprintf — 2.0 сек

и это при миллионе итераций, что не часто встретится в реальном проекте.
При записи через запятую расход памяти сокращается, но её объём сильно зависит от длины строки.

В пользу записи через точку могу привести пример.
При рефакторинге потребовалось заменить вывод echo 'some' . 'string' на присваивание значения переменной $var .= 'some' . 'string'. Как вы понимаете мне достаточно было заменить «echo» на "$var .=", не выискивая запятые, т.к. она не является оператором конкатенации.
Вообще-то для более честного результата мне следовало делать замер времени внутри функций буферизации, но после проверки оказалось, что это влияет несущественно )
Для более честного результата стоило взять размеры коктенируемых значений более близкие к реальным, если мне не совсем отшибло память, давно с работой интерпретатора разбирался, то скорость падает с увеличением размера переменных, как и объем занимаемой памяти увеличивается тоже с ростом размера.
echo join( array( '<option ...>',$node['name'],'' ) );
На больших строках сравните. Разница бывает в сотни раз ;)
С объединением через точку согласен, А вот вывод через запятую сдается мне будет всетаки быстрее…
Да, RainTPL — отличный шаблонизатор. Всего один небольшой php файл, а может практически тоже самое, что монстр Smarty, по крайней мере все мои нужды покрывает. Я чуть допилил его для себя и с удовольствием пользуюсь уже пару лет.
Верю, что он покрывает Ваши нужды, но утверждать, что он «может практически тоже самое, что монстр Smarty», мягко говоря, некорректно. Навскидку не вижу таких вещей, как расширяемость с помощью сторонних компонентов (функций/фильтров/модификаторов), кеширования скомпилированных шаблонов, наследования шаблонов — вещи, которые, с моей точки зрения, и придают шаблонизаторам особую ценность.
Во-первых MVC и все такое, так что лучше разделять логику и представление, и вообще если у вас в шаблоне что-то сложное, значит что-то вы делаете не так в логике контроллера.
Во-вторых пожалейте верстальщиков, которым намного легче выучить простые 5 конструкций шаблонизатора, чем смотреть на ваш PHP код.
У меня есть один проект где смарти и код хранится в бд, php код в бд это особенно меня радовало, когда я только начинал с ним разбираться ищешь поиском на диске нужный код, а его нет.
А теперь к потребностям шаблонов.
Автоэкронирование html, js, css
Наследование, кэширование блоков, переопределение блоков.
Буферизация, тримминг, вырезание лишних пробелов и т.д.
Итерации — первая, последняя, вывод в две колонки

Давайте скажем проще, вы никогда не использовали смарти, а просто заменили свои ## на {{}}, так что и с переходом вы ничего не потеряли.

Кажется, примеры специально подобраны, чтобы показать, какой страшный Smarty и какой приятный pure php.

А если у представления чуть более сложная логика, чем тупо показать подготовленные данные:

{$var|escape 'html'|upper} против <?= htmlspecialchars(strtoupper($var));?> или даже <?php echo  htmlspecialchars(strtoupper($var));?>


Smarty 3 давным-давно «умеет» более простые объявления переменных и прочую математику, мучаться с assign уже не обязательно:

{$var = $a + $b;} против <?php $var = $a + $b; ?>


Про рекурсивное дерево — {function} уже упомянуто выше.

И странное утверждение о том, что Smarty должен быть удобнее для дизайнеров — дизайнеры обычно только рисуют, а html-код готовят верстальщики, а не дизайнеры. И им гораздо проще разобраться в Smarty и его возможностях, чем изучать язык PHP, чтобы понять, что навернуто в шаблонах. А если программист отвечает еще и за верстку — то это вопрос к организации процесса, а не к Smarty.

Я использовал pure php в шаблонах и лично мне очень не нравится мешанина из <?-тегов, в которые это в итоге выливается (что еще и читаемость затрудняет — труднее отделить визуально html-тэги от php-тэгов):

Smarty:
<table>
<tr><th>{'Header'  |  i18n | escape 'htmlall'}</th><th>{'Name'  |  i18n | escape 'htmlall'}</th></tr>
{foreach $table as $row}
<tr><td>{$row.header | escape 'htmlall'}</td><td>{$row.name | escape 'htmlall'}</td></tr>
{/foreach}
</table>


То же самое на php:
<table>
<tr><th><?=  CHtml::encode(Yii::t('', Header' )); ?></th><th><?= CHtml::encode(Yii::t('', 'Name')); ?></th></tr>
<?php foreach($table as $row) { ?>
<tr><td><?= CHtml::encode($row['header']); ?></td><td><?= CHtml::encode($row['name']); ?></td></tr>
<?php } ?>
</table>

UFO landed and left these words here
Ад? Откройте любой шаблон битрикса.
Любой мало мальский дизайнер или просто хорошший программист запустит вам в лицо крайне тяжелым предметом если увидит в файлах шаблонов — пхп код.

А по поводу смарти — вы просто не умеете его готовить. Совсем.
Да что уж там:
Проще? Нет.
Понятнее? Нет.
Быстрее? Возможно.
Безопаснее? Нет.

А если еще и взять вместо smarty нормальный шаблонизатор…
А какой нормальный, на Ваш взгляд?
Понятно. Меня Твиг не устраивает
Вы наверное не используете наследование в шаблонах, раз говорите что голый php лучше?
Наверное вообще в шаблонах ничего не использует
Гос-ди б-же, какой смысл в этой статье? Что автор хочет донести до нас?
Что автор хочет донести до нас?

То, что 2-3 года назад перестал использовать Смарти
Ясно. Надеюсь будет держать в курсе и дальше.
Ждем статьи о том, как автор ушел с php 5.2
Прежде всего я хотел рассказать тем, кто только начинает писать: не стоит хвататься за что-то, без чего можно обойтись (как в моем случае), как бы это ни казалось круто и модно. И больше думать, что даст та или иная технология проекту и вам лично.
То что он отстал в технологиях лет так на 10
Верстальщик. Использую Smarty больше 5 лет, нравится, доволен, отлично разделяется логика от представления. Все доводы против прочитал, спасибо, но не надо. Мне кажется тот, кто пишет php код в шаблонах попросту многостаночник — архитектор, дизайнер, программист, верстальщик в одном лице. Ему наверное проще. Кстати, MVC тоже прекрасно пишется в одном файле.
Даже в простых вещах, как вывод значения переменной не знаю как в смарти, а в твиге все очень круто сделано.

{{ user.status }}

Тут твиг пройдется по стеку возможных использований: массив, объект с открытым полем, геттер. Если такая конструкция используется в условии — проверит has/is.
А еще фильтры… В php не все объекты, так что user->getStatus()->ucfirst() не получится. А что если нужно использовать несколько функций? А как разделить логику получения свойства от логики ее изменения? В шаблоне все четко понятно:

<?= ucfirst(e($user->getStatus())); ?>

{{ user.status | e | capitalize  }}
Согласен. Сам был раньше сторонником «чистого PHP» в шаблнах, но понял что все мои беды были не от шаблонов, а от Smarty =) Перешел на Twig и полюбил шаблоны :)

Банальный пример — с чистым PHP — данные (например дату отформатировать) нужно для вывода либо подготавливать в логике, либо писать уродливые длинные вызовы функций со скобками в шаблонах…
Да и «чистый PHP» по умолчанию не будет «чистым», потому что какой-никакой свой шаблонизатор навертеть вокруг шаблонов нужно — хотябы чтобы все переменные по умолчанию ескейпились, что облегчает работу, скокращает код/улучшает читабельность и по умолчанию повышает секьюрность, так как проескейпить переменную можно просто забыть. Твиг и новый Смарти (вроде) делают это по умолчанию.
Твиг является наследником смарти, поэтому в смарти точно так же, только синтаксис чуть-чуть отличается: {$user.status}, {$user.status|@e|@capitalize}
Громко называть twig наследником смарти)
Twig uses a syntax similar to the Django and Jinja template languages which inspired the Twig runtime environment.

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

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

Если мы посмотрим на скомпилированные шаблоны твига, то увидим что код в них написан максимально оптимально (хоть зачастую и нечитаемо совсем). Те же блоки — просто методы класса, поэтому наследование — шаблонов — обычное нативное наследование классов в php. Ввиду изложенного мы понимаем что твиг как минимум не проигрывает в скорости нативному php.

Мой выбор — твиг.
Какое винтажное решение однако. По мне так если в HTML шаблоне находиться что-то кроме HTML, ну и максимум каких-то флагов, вроде {VALUE}, то это уже нарушение MVC. Внутри шаблона не должно быть условий, ветвлений и преобразования типов. Если что-то такое там есть, то верстальщик всегда может поломать логику и пойдет игра в тяни-толкай, когда одни правят баги логики, вторые фронт-енд и так до упора, по кругу.
Под мои принципы подходят самые простые варианты, вроде: www.phpxtemplate.org/ (сам юзаю самописный парсер, но синтаксис почти 1 в 1 как XTemplate)
Внутри шаблона не должно быть условий, ветвлений и преобразования типов

Спорно. Надо вывести табличку под данным — вот уже цикл есть. Надо табличку раскрасить в разные цвета по строкам для лучшей читаемости — вот уже и ветвление (это точно не задача контроллера или модели в MVC), а еще форматирование данных при выводе и тому подобное.
Чтобы вывести несколько строк внутри таблицы, секция с шаблоном строки задается один раз, иначе будет нарушение не только MVC, но и DRY, раскрасить в разные цвета можно через переменную (надеюсь сообразите сами как, теги не работают, чтоб пример написать), за то, сколько раз строку рисовать отвечает логика, а не шаблон. Конечно можно намешать HTML с PHP или псевдоязыком парсера, формально не нарушая MVC, но я не просто так описывал, что дело помимо прочего в разделении доступа \ зоны ответственности верстальщика и программиста.
Форматирование я выношу в логику тоже, конечно хочется чего-нить такого дописать, чтоб хотя бы строки экранировало, да даты через конфиг менялись, но ничто не мешает добавить умный флаг, в назначение значения со стороны логики, сложнее не станет, а чистота шаблона сохранится.
Чтобы вывести несколько строк внутри таблицы, секция с шаблоном строки задается один раз

А я где-то говорил обратное? А для того, чтобы вывести несколько строк с одним шаблоном, вам цикл же надо? А цикл разве не является как раз ветвлением + условием?

раскрасить в разные цвета можно через переменную (надеюсь сообразите сами как, теги не работают, чтоб пример написать),

Не сообразил. Напишите как. Напоминаю исходные условия: в шаблонах ветвлений нельзя, условий нельзя. Части model и controller за отображение не отвечают никак. Как именно в таких условиях обеспечить раскраску строк таблицы?

за то, сколько раз строку рисовать, отвечает логика, а не шаблон...

WAT? Логику в идеале вообще не должно волновать, как именно ее данные там рисуют.

Проверьте свои рассуждения таким образом. Возьмите проект и решите, что теперь мы будем возвращать не html, а, например, json. Если в коде частей model и controller при этом что-то надо менять (или удалять), то что-то не так (с определенными оговорками, конечно, но тем не менее). Лично я не вижу ничего плохого в том, чтобы логику отображения писать непосредственно в этом отображении.
Еще раз обращу ваше внимание, что я делю проект на логику и шаблоны, не как понятия модель-представление из MVC, а как практические сферы для программиста и для верстальщика (а то и вовсе девушки секретарши, которой надо быстрый хотфикс сделать по требованию босса). Таким образом если вы возьмете XTemplate например — сам класс его будет называться не представлением, а логикой, а шаблон, это HTML файл который передается для создания объекта, с этой стороны тест на формальный MVC не будет пройден, потому что если нам надо будет генерить json, то изменения затронут XTemplate (или его наследника), а мы их обозвали логикой. Если вы хотите придерживаться MVC терминологии — пожалуйста, но внутри представления тогда должно быть еще одно деление, на логику-представления и HTML шаблон.

Главная мысль в том, чтобы максимально отчистить шаблон, сделав его безопасным для редактирования пресловутой секретаршей, как-то так это выглядит в синтаксисе XTemplate:
jsfiddle.net/2FWpU/3/
(В JS секцию код на PHP я запихал)
Спорный момент там в том, что имя CSS класса для раскраски приходиться в логику пихать, но это на мой взгляд меньшее зло.
Шаблоны в MVC в наименьшей степени предназначаются для секретарш. То что вы описываете, это компонентная система, прямо противоположная MVC. Там в шаблонах вставляются компоненты, у которых можно задавать разные характеристики и да нет циклов и да, легче для секретарш. Но это не MVC, хотя внутри компонент может содержать эту архитектуру.

А компонентная система слишком громоздка и затормаживает разработку, поэтому ее используют в основном в CMS для не специалистов.
Не знаком с таким термином, гугл тоже не в курсе, по запросу «компонентная система» что-то там про колонки вешает. Компонентная архитектура тоже не о том, ее можно еще как-то к фронтенду применить, но у нас речь именно о серверной части и в HTML мы никакую привязку к событиям не делаем, так что компонентами их назвать нельзя.
Так или иначе, не соглашусь, что подобный подход затормаживает разработку. В моей практике реально, случаев, когда очень уж сильно хочется условный оператор зафигачить в шаблон 1% от всего проекта, а лет через 5 подобной практики даже это редкое желание уходит. В то время как от Smarty-подобных подходов жжение от батхерта в процессе дебага и поддержки у меня только увеличивалось год от года.
Впрочем я не претендую на истину в последней инстанции, возможно это связанно со спецификой моих проектов и заказчиков (последние расселены от Штатов до Австралии, что провоцирует острое желание научить их самих делать хотфиксы, а не будить меня по ночам, если нужен какой-то срочный апдейт фронтенда).
Ну компонентная система это абстрактное понятие, когда система состоит из кусочков, которые можно собирать воедино, как конструктор. Не обязательно компонент может быть основан только на событиях. Но принцип в том, что в шаблон вставляется компонент, который пользователь может конфигурировать, т.е. менять его параметры. В параметр компонента может даже входит какая-то часть шаблона, например список новостей, а у него есть мини-шаблон-параметр для выводя элемента новости и т.п., есть параметр кол-во новостей на странице. Да циклов нет, условий нет, вся логика скрыта внутри компонента. Конечно, желательно конфигурирование шаблона должно быть в гуи.
Включение чистого PHP в Smarty.
Уж коли он по какой-то причине нужен. Иными словами да здравствуют холивары…
Smarty — примерно такая же обёртка над PHP, как jQuery над JS. Абстракция. Хочешь — используй, не хочешь — не используй.
Привет основной теореме программной инженерии.
Only those users with full accounts are able to leave comments. Log in, please.