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

    За предвкушением 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
    Share post

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 14

      +2
      Напрашивается сравнительное тестирование уймы PHP-шаблонизаторов
        0
        Слова «сравнительное тестирование» для меня звучат зловеще. Если често, то я не уверен, что в сравнительных тестированиях есть толк, в смысле их полезности для кого-либо, кроме тестирующего.

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

        Поэтому для себя я просто сравниваю. Без тестов.

        Впрочем, мои тараканы, конечно же, ни к коей мере не мешают производителям шаблонизаторов, например, замерять скорость работы. А эти данные обычно имеются в открытом доступе на сайтах производителей.
        0
        Разрешите проявить взаимный академический интерес, не холивара ради:
        жизненно необходимо для поддержвания качественных и количественных показателей работы

        Можно какой-то пример из жизни или что-то подобное?

        Просто лично мне трудно представить себе конфигурацию, когда данные проблемы может хоть немного помочь решить шаблонизатор.
        Мне всегда казалось, что он этих проблем добавляет, однако я могу ошибаться.
          0
          Не понял, конфигурацию чего вы имеете в виду, но в качестве запрошенного примера могу предложить описания из разделов статьи «Синтаксис» и «Безопасность», то есть это опять-таки разговор о количестве логики, которую можно вынести в шаблоны — об уровнях абстакции. Если для вас дополнительный слой логики обоснованно избыточен — не нужно его использовать. Проводя аналогию: ООП — это тоже слой абстракции, без которого люди успешно обходятся и будут обходиться.

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

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

          И на всякий случай поясню, что «жизненно» из цитаты относится к успешности существования проекта, а не его участников %)
            0
            > если поручить работу над шаблонами лицу, не связанному с программированием

            я вот по этой причине когда-то использовал tal — он добавляет xml-атрибуты к тегам, это гораздо удобнее верстальщикам(даже wysiwig-редакторы такие шаблоны не ломают)
              0
              > Не понял, конфигурацию чего вы имеете в виду

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

              Относительно Синтаксиса:

              Все говорят про какой-то абстрактный порог вхождения. Вот честное слово, такое чувство будто человек который будет заниматься версткой это медицинский дебил. Просто если это так, то зачем ему вообще поручать заниматься версткой?

              Давайте уже не кривя душей скажем, что 95% кодинга верстальщика покрывается в этих командах (Smarty):
              <?=$foo?>
              {$foo}
              
              <?=$foo['bar']?>
              {$foo.bar}
              
              <?php foreach($foo as $bar){ ?> a <?php } ?>
              {foreach $foo as $bar}a{/foreach}
              
              <?php if($foo=='Fred '){ ?>  yes<?php }else{ ?>  no<?php } ?>
              
              {if $name == 'Fred' '}   yes{/if}{else}   no {/else}
              
              <?php include('page_header.tpl');?>
              {include file='page_header.tpl'}
              


              Не совсем понимаю, где тут порог вхождения проще.
              Он вообще одинаковый.

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

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

                Странное чувство. Непонятно, откуда оно у вас. Речь шла о том, что людям, занимающимся дизайном/вёрсткой должно быть не досуг думать о том, как, например, обратиться к атрибуту сущности (вне зависимости от того, массив это, скажем, или объект), как обработать ошибку доступа к методу объекта, и в том же духе, — им бы вместо этого свою работу выполнять и другим проблем не создавать.
                Давайте уже не кривя душей скажем, что 95% кодинга [...]

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

                Ну, я тоже, к примеру, не видел, чтобы поклонение шаблонам проектирования имело какое-то реально положительное влияние на проект, а некоторые божатся, что такое имеет место быть %)
            0
            а почему не jinja был взят за основу? синтаксис почти такой же, а гвоздями не прибит и django и быстрее.

            p.s. забавно, когда-то, когда писал на php использовал шаблоны tal, а это тоже порт с zope
              0
              Джинжу Армин срисовывал с Джанго, не удивительно, что синтаксис «почти такой же».

              Портировать Джинжу полноценно не получилось бы в любом случае: Армин пытался, но понял тщетность затеи. Потом, правда, идею подхватил Фабьен в своём Твиге, адаптировав под реалии PHP — и со скоростью у него всё в порядке вышло, да только в области расширения случился прокол — слишком накладно писать свои теги.

              забавно, когда-то, когда писал на php

              Скорее закономерно: идеи кочуют. Хорошо, когда это хорошие идеи %)
                0
                > идеи кочуют

                кстати, в современных версиях php с этим стало проще. те же замыкания/анонимные функции очень помогают.

                p.s. когда-то писал конвертер python->php для ограниченного подмножества python. github.com/idlesign/dja/blob/master/dja/dja_pyhelpers.php — ох как бы мне пригодилось тогда:) но и сам python выручал — начиная от модулей типа lex до разбора ast
                  0
                  кстати а у php есть байткод сейчас или это классический интерпретатор? я вот сейчас подумал что можно было бы пойти более низким уровнем.
                    0
                    Есть-то он есть, да не про нашу честь %)
                    0
                    да только в области расширения случился прокол — слишком накладно писать свои теги.

                    Вы что-то путаете, расширение Twig предельно простое занятие — свой тег можно за 5 минут написать.
                      0
                      Видимо у нас с вами разное представление о простоте. Я бы ты не стал писать тег пять минут %)

                Only users with full accounts can post comments. Log in, please.