Pull to refresh

Шаблоны в шаблонизаторе и как шаблоны Django до PHP дошли (в очередной раз)

Reading time 5 min
Views 7.8K
За предвкушением 23-го февраля можно даже и не заметить, как вечер четверговых разговоров о шаблонизаторах для PHP может плавно перетечь в вечер пятничных.

В статье будет рассмотрено несколько тем, начиная с темы нужности шаблонизаторов вообще и в PHP в частности, и заканчивая заметками о процессе создания шаблонизатора dja (портировании кода с Python на PHP).


Про шаблонизаторы



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

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

Важно понимать, что необходимость использования или не использования шаблонизатора должна диктоваться прежде всего задачей. Да, это древняя мантра — «инструмент подбирается под задачу» — и здесь она тоже работает.

Если это проект человека (или нескольких), которого не коробит от <? в коде шаблонов, если он знает, что делает, для кого, зачем он это делает, и осознаёт возможные последствия, то это замечательно. Это люди с железной волей, и, часто, умеющие подчинить ей других.

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

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

  • Синтаксис
  • Безопасность
  • Скорость работы


*На досуге можно придумать еще несколько или перетасовать указанные по приоритетности.

Синтаксис


Важен потому, что он влияет на порог вхождения и на скорость разработки шаблонов (последнее часто нивелируется при использовании IDE). Чем проще и логичнее синтаксис, тем быстрее верстальщики (те самые, о которых не слышали нигде, кроме России сотоварищи) выдадут результат.

Безопасность


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

Дозволенный уровень логики влияет на то, каких дел может наворотить создатель шаблона. Понятно стремление большинства иметь в шаблонах ровно столько логики сколько нужно и что больше не надо. Проблема только в том, что «сколько нужно» у каждого своё — с одной стороны доносятся крики: «Зачем шаблонизатору elseif — это уже попахивает бизнес-логикой», — с другой: «А нам надо иметь возможность в шаблоне запускать процесс ОС». Тут-то и возникает понятие «расширяемости».

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

Скорость работы


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

Dja. Про портирование с Python на PHP



О том, что такое dja вкратце можно узнать из анонса).
О том для чего и в какой манере было произведено портирование можно узнать из описания dja на github, а этой главе я расскажу о том, скольких приседаний стоило портирование.

Разбить каркас


Прежде всего стоит упомянуть, что Django — это полновесный каркас для разработки веб-приложений на Python, а движок шаблонизатора — его немалая часть. И чтобы изъять одно из другого требовалось отследить зависимости и спроектировать суррогатные заглушки для частей каркаса, напрямую соприкосавшихся с ним. Так появились встроенные интерфейсы — чрезвычайно упрощенные заменители смежных подсистем Django, которые, однако же, могут быть замещены пользовательскими разработками.

Быть ближе к источнику


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

Не секрет, что некоторые функции со сходным назначением в Python и PHP сильно различаются сигнатурами, а некоторых там или там может просто не быть. Сравните, например параметры str_split() и ''.split(), Reflection* объекты и функции модуля inspect, или типы данных, возвращаемых в качестве совпадений (match) функциями для работы в регулярными выражениями.

Само существование таких адаптирующих заменителей подразумевает расходы на их исполнение, но эстета в себе временами чрезвычайно сложно задавить.

Чтобы быть ещё ближе к источнику в PHP не хватало:
  • Аргументов-ключевых-слов
  • Ветки finally в обработке исключений
  • __iter__ дескриптора вместо интерфейса Iterator
  • Частичного связывания аргументов типа functools.partial()


Различия в областях видимости переменных внутри метода и отсутствие в PHP синтаксического сахара для создания декораторов пришлось компенсировать замыканиями (сравните: dja, Django), по большому счету довольно удачно.

Упростить создание библиотек тегов и фильтров


Расширить функциональные возможности Django можно реализовав свои теги и фильтры. Для упрощения их регистрации в коде библиотек на полную используются декораторы. Для dja пришлось придумать альтернативный путь — здесь на помощь пришли анонимные функции.

Сравните (регистрация фильтра lower):

@register.filter(is_safe=True)
def lower(value):
    return value.lower()


$lib->filter('lower', function($value) {
    return strtolower($value);
}, array('is_safe' => True));


Таким образом, анонимные функции можно назвать палочкой-выручалочкой, при портировании кода с Python, изобилующего декораторами, на PHP, в частности dja — это торжество анонимных функций. Ни в одном другом проекте на PHP я не видел их в таком количестве.

Портировать тесты


Django славится своим набором тестов, поэтому стыд и позор было бы не импортировать хотя бы часть этой кладези мудрости. Убеждён, что хотя бы друхкратное чтение перед сном кода регрессивных тестов сделает вас духовно богаче (осторожно скобки, берегите глаза!).

Победить монотонность


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

Это, пожалуй, всё, что я хотел сказать.
Спасибо за внимание. Удачи в портированиях.

P.S.: И да, я тут с удивлением обнаружил, что dja «набирает обороты». Это не правда %P
Tags:
Hubs:
+2
Comments 14
Comments Comments 14

Articles