Zend Framework 2 — долгожданные усовершенствования в Controller и View

    image На днях попробовал новый ZF2. Перечитал кучу материала, собрал по их туториалу простенький сайтик. И когда дошел до создания Action'а и View'хи то пределу моей радости не было границ. Передача переменных во view теперь осуществляется через return, и они стали локальными (никакого $this->param). Только ради этого усовершенствования я готов уже сейчас переходить на ZF2, несмотря на то что он в бете.

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


    Новшества ZF2, о которых говорят все:

    • улучшена производительность
    • используются более гибкие подходы, улучшения в стандартизации и унификации
    • переработана модель работы с плагинами
    • повсеместное использование namespace'ов
    • больше никаких вызовов require_once внутри компонент (всё через автолоадер)
    • 2 новых основополагающих компонента Dependency Injection и EventManager (DI вещь бесспорно классная, но пугает своей магией установки параметров в объекты по названию переменных в методах. Обычно такая магия негативно сказывается на производительности. EventManager удобная штука. Логирование, кеширование, пре- и пост-обработка данных теперь на высшем уровне)
    Разработчики постарались и сделали достойный ZendSkeletonApplication — это простой скелет приложения, использующий слой ZF2 MVC и модули системы. Скелет использует свободный инструментарий css и html от твиттера. Получаем симпатичный web2.0 сайтик из одной странички, который легко раздуть до полноценного сайта.

    Касательно производительности ZF2

    • за счёт новых автолоадеров, Class Map даёт до 85% улучшения производительности по сравнению с ZF1
    • использование namespace'ов до 40% (сперва думал, что это незначительная плюшка в PHP5.3 и носит чисто эстетический характер)
    • уменьшено кол-ва вызовов при использовании плагинов (7 вызовов вместо 13, думаю можно говорить о двукратном ускорении)
    • рефакторинг MVC (должно точно дать ощутимый прирост производительности. На порядок улучшилось удобство использования.)
    Тяжело оценивать, но смело предположу, что производительность возрастет не меньше чем в два раза.

    Долгожданные усовершенствования в Controller и View


    Наконец-то, совершилось! В action-контроллерах передача переменных перестала быть магией. Вместо некрасивых $this->view->..., теперь action должен возвращать ассоциативный массив с данными для вьюхи. Приведу примеры для сравнения.

    Было ZF1:
    public function indexAction()
    {
        $this->view->albums = $this->albumTable->fetchAll();
        $this->view->user = 123;
        $this->view->text = 'any <html> it will not be automatically escaped in view';
    }

    Стало ZF2:
    public function indexAction()
    {
        return array(
            'albums' => $this->albumTable->fetchAll(),
            'user' => 123,
            'text' => 'any <html> it will be automatically escaped in view',
        );
    }


    View шаблоны тоже преобразились в лучшую сторону. Переменные стали локальными (доступны по их названию), а хелперы остались доступны через $this->helper(). Все строковые переменные автоматически эскейпятся, во избежании XSS. Массивы и объекты остаются без изменений, поэтому при выводе из них значений необходимо пропускать через $this->escape();
    Писать и читать код стало удобнее.

    Было ZF1:
    <?php 
        $this->headTitle('My albums');
    ?>
     
    <?php 
        foreach($this->albums as $album) {
            // some code
        }
    ?>
     
    <?php 
        echo $this->escape($this->text); 
    ?>
     

    Стало ZF2:
    <?php 
        // хелперы всё также доступны через $this
        $this->headTitle('My albums');
    ?>
     
    <?php 
        // альбомы из action'а из примера выше стали доступны через локальную переменную
        foreach($albums as $album) {
            // some code
        }
    ?>
     
    <?php 
        // нет необходимости вызывать escape, все скалярные значения автоматом эскейпятся
        // массивы и объекты пропускаются и во view попадают как есть
        echo $text; 
    ?>
     

    На мой взгляд это самое «вкусное» усовершенствование в ZF2.

    Как попробовать и что почитать


    Zend Framework 2 находится в состоянии beta. Где-то видел, что stable release будет весной 2012. Но использовать на свой страх и риск его можно уже сейчас.

    Обязательно ставьте последний PHP 5.3.8. На PHP 5.3.2 у меня выскакивала ошибка Strict Standart.
    Под виндой мне пришлось ставить новый апач 2.4 скомпилированный под VC9. Качать PHP x86 TS VC9 отсюда, экстеншены apc и mongo отсюда, php_xdebug.dll подобрать на официальном сайте отправив в формочке свой phpinfo.

    В первую очередь прочтите хорошую статью на русском «Zend Framework 2. Материалы для изучения» на сайте tokarchuk.ru.

    Потом воспользуйтесь замечательным туториалом Getting Started with Zend Framework 2 (PDF, en), с помощью которого вы за час-два установите ZF2 и создадите тестовый модуль «альбом».

    Комментарии 59

      +5
      Пардон, но не удержался: «7 вызовов вместо 13, думаю можно говорить о 90% ускорении» Вот это математика)
        0
        Не проблема, заменил 90% на двух-кратное ускорение, чтоб глаз меньше резало. Математика проста, было грубо говоря 14 вызовов, стало 7 — в два раза возросла производительность.
          +2
          *двукратное
        –1
        Вам какбе намекают, что в два раза — это на 50% быстрее.
        На 90% быстрее — это значит, что было 10 секунд, а стало 1 секунду.
        Ваш, КО.
          0
          Задачка для третьего класса гик-школы:
          Ваш код обрабатывал 1000 запросов в секунду. Затем вы его рефакторнули, и он стал на 50% быстрее. Сколько запросов в секунду стал обрабатываль ваш скрипт.
          Ответ: 50% от 1000 = 500, следовательно, ваш код стал обрабатывать на 500 запросов в секунду больше. 1000 + 500 = 1500 запросов в секунду.
          Задачка со звёздочкой: Сколько запросов станет обрабатывать ваш код при ускорении его ещё на 90%?
            +1
            Большинство гиков отчалило из класса, сразу после решения 1й задачки.
            Гик != Отличник
              0
              Ну, я не очень понимаю, что в моём сообщении привело вас к умозаключению, что я считаю гиков отличниками, но держите нас в курсе, да =)
              –1
              Вы говорите о производительности, а не о быстроте выполнения. Подмена понятий.

              Время выполнения одной операции — сек. (время)
              Количество операций в секунду — оп/сек. (производительность, она же мощность в физике) (дробь тут очень важна)

              Секунд на одну операцию: 1
              Операция в секунду: 1

              В два раза быстрее:
              Секунд на операцию: 0.5
              Операций в секунду: 2

              Автор не пишет про ускорение, а не о приросте производительности.

              PS: мощность — количество выполненой работы в единицу времени. Если бы вы вспомнили не о 3-ем классе, а хотябы о седьмом-восьмом, то точно бы осилили.
                0
                * Автор пишет про ускорение, а не о приросте производительности.
                  0
                  какую тут крутую дискуссию завернули. все у автора было верно:
                  если производительность/скорость/ещечтото увеличилось в 2 раза — это значит на 100%,
                  если же почти в 2 раза — то можно написать на 90%
                  +1
                  точно бы осилили
                  лол, баттхёрт. ясно.
                  Вы говорите о производительности, а не о быстроте выполнения.
                  оО
                  Вы здоровы? Производительность и «быстрота», она же скорость, в текущем контексте есть одно и то же, и все они выражаются в «чем-то за время» (например, км/ч, лол/мин, оп/сек). А то, что вы выражаете в секундах, это время выполнения, и о нём ни в оригинальном сообщении, ни в вашем нет ни слова.
                  Автор пишет про ускорение, а не о приросте производительности.
                  Так, ускорение. Значит, меняется скорость, так? Скорость в чём измеряется? А, точно, это же то же самое, что и производительность в нашем контексте — оп/сек.
                  Перевожу на человеческий: ускорение на 90% значит, что скорость возросла на 90%, то есть, например, со 100 до 190 км/ч. Вот если бы речь шла об уменьшении какого-то показателя, то вы были бы правы — но увы и ах, об уменьшении речи нет, а уменьшение времени есть лишь следствие увеличения скорости (производительности), которое вы додумали и выпячиваете в попытке показать, быдто бы вы что-то там осилили.
                    0
                    Нет разницы увеличиваем или уменьшаем показатель. Ехали 100 км\ч замедлились на 90% — едем 100 — 90 = 10 км\ч.
                      0
                      Я имел ввиду перевод из сложения/вычитания в умножение/деление, блестяще проведённый автором исходного комментария: «в два раза — это на 50% быстрее» — ну нормально, нет? =) А так-то вы правы, разумеется.
                        +1
                        «в два раза — это на 50% быстрее» — ну нормально, нет? =)

                        Иногда кажется, что маркетологи тоже не видят разницы между «в два раза и на 50%» :)
                          0
                          А она есть?
                            0
                            Вы таки маркетолог?
              +1
              Долгожданным усовершенствованием будет превращение фронт контроллера в стейт машину, как было и заявлено еще года 4 назад.

              Просто if/else конструкции монстрообразные уже. Не говоря о том, что в принципе все идет к этому. Сейчас в зенде уже фактически есть стейты — диспатч, роутинг. ПабСабы нам обещали когда? Я помню еще ЗендКонфу 2009 года в Питере, когда нам и анонсировали их.
                0
                Спасибо за ссылки и за новость, интересно.
                  +3
                  а я в первом зенде всегда делал так:

                  $this->view->assign(array(
                       'albums' => $this->albumTable->fetchAll(),
                       'user' => 123,
                       'text' => 'any <html> it will be automatically escaped in view',
                  ));
                  


                  логичнее было бы сравнивать именно этот вариант
                    0
                    согласен.
                      +1
                      It will not be automatically escaped in view.
                        0
                        метод assign это обертка, которая точно также обращается к магическому методу __set
                          0
                          В первом зенде ничего автоматом не эскейпилось во view.
                            +2
                            мой комментарий был о другом, впрочем уже не важно
                              0
                              О чем ваш коммент понятно, я просто указал на текст, мол надо как в примере. Я просто забыл написать в конце слово «лопата».
                      +1
                      Имхо, плохо, что стринги эскейпятся, а массивы стрингов — нет.
                      В запарке можно об этом позабыть, и если вдруг понадобится передать из контроллера два текста вместо одного, могут возникнуть проблемы:
                      Было:
                      return(array('text'=>'blabla'));

                      echo $text; // проблем нет

                      Задание, добавить несколько текстов:
                      return(array('text'=>array('blabla', 'foo')));

                      foreach($text as $txt) echo $txt; // нужно эскейпить

                      Как раз недавно столкнулся с похожей проблемой в typo3: при посте формы из скалярных параметров удалялись пехапешные эскейпы, а из массивов — нет.
                        +1
                        Действительно, это очень коряво. Во-первых, как вывести оригинальный текст? Анэскейпить, или передавать единственным элменетом массива? Во-вторых, намного полезнее было бы сделать шорткат для $this->escape(): q($text). С неймспейсами это как раз бы хорошо получилось.
                        +2
                        По мне так самым вкусным в ZF2 стали DI и Events
                          –1
                          Они уже и так есть в Symfony2. Интересно, чего Зендовцы переписывают велосипеды?
                          Ну честно, если бы добавили новые компоненты, или какие-то интересные архитектурные решения…

                          А то сейчас получится 2 почти идентичных фреймворка с похожими возможностями.
                          Отличия только в бренде.
                            0
                            Ну, есть они не только в Symfony2, и не в ней первой появились. Так что, видимо, и у симфонистов тоже были причины «изобретать велосипед»

                            > Ну честно, если бы добавили новые компоненты, или какие-то интересные архитектурные решения…

                            Хм… архитектуру ZF практически полностью переписали, Вам этого мало?! :)
                              0
                              Они уже и так есть в Symfony2. Интересно, чего Зендовцы переписывают велосипеды?

                              Они интегрируются друг с другом, как раз для того, чтобы не писать велосипеды. Например компонент Yml из Symfony есть и в нём, и в ZF, и в Doctrine. Это плохо? По-моему просто отлично, когда каждый занимается своим делом, а не пишет «свою CMS». Разве нет?

                              А то сейчас получится 2 почти идентичных фреймворка с похожими возможностями.
                              Отличия только в бренде.

                              Нет, всё с точностью наоборот. Бренд — тот же, фреймворк совершенно другой. Начав с внедрения неймспейсов и фишек php 5.3 зендовцы вошли в раш и используют его преимущества на всю катушку. Основная цель — увеличение производительности. Вы сравните два Skeleton Application. Взять хотя бы диспетчеризацию, построенную на событиях и старый цикл диспетчеризации. Всё по другому, я бы сказал на новом уровне.
                                +1
                                Вы не так поняли комент Davert-а. Он говорит о том, что есть уже симфони2 с Di, а зендовцы свой изобрели. И говоря о двух одинаковых фреймворках под разными брендами, он имеет в виду Symfony2 и ZF2, а не ZF1/ZF2
                                  0
                                  Понял, пардоньте. Ну у ZF и Symfony свои пути развития. Symfony — монолит, ZF — конструктор.
                                    0
                                    Вот именно. Вы полностью подтверждаете мои слова про бренды!

                                    Вы не заметили, что Симфони2 уже далеко не монолит, а тоже набор компонентов, и наверное, даже более независимых. Посмотрите немного на Symfony2, и на Symfony Components.

                                    Проблема в том, что в Симфони под единым названием существут 2 разных фреймворка и не все ещё это знают.
                                      0
                                      Да, я в курсе про Symfony components. Умный шаг. Идут в сторону конструктора, но всё же Symfony по своей природе именно монолит. ZF гораздо гибче и абстрактнее.
                                      Про бренды полностью согласен. Такая фигня и с ZF, и с Symfony, и с Doctrine.
                                        –1
                                        Ну насчет гибче абстрактнее… Symfony сейчас как раз и продвигается как компоненты.
                                        Вон уже 8ой друпал будет их использовать. В чем там монолитность пока непонятно. ВЗять те же бандлы… Они намного менее привязаны к конкретному проекту, чем что либо в Зенде.

                                        Вообщем, у меня есть некоторое разочарование. Я надеялся, что в Зенде будут какие-то новые оригинальные архитектурные решения. А их нет (
                                          0
                                          ВЗять те же бандлы… Они намного менее привязаны к конкретному проекту, чем что либо в Зенде.

                                          Модули ZF2 смотрели? Теже бандлы. Можно реализовать специфическую для проекта функциональность, а можно решать общую задачу (уже появилась куча модулей этим занимающихся, например, реализация регистрации/авторизации пользователей)
                                            0
                                            Не сравнивал их, так один в один.
                                            Если сможете сравнить их в статье, буду крайне благодарен )
                                      0
                                      Symfony никогда не планировалась как монолитный фреймворк. Только на первом релизе это скорее выражалось в использовании сторонних компонентов, таких как Propel \ Doctrine, потом, после релиза версии 1.2 большой шаг к разделению был приход sfForm и теперь Symfony2 уже практически полностью состоит из разделенных компонентов.
                                        +1
                                        Та не надо. Был достаточно жесткий каркас, аки Rails.
                                        И компоненты, как ни крути, выпиливать приходилось из общего ядра.
                                        Он был монолитным, но это было даже хорошо ) Каркас приложения не приходилось строить из кубиков.
                              +1
                              Не понимаю, зачем делать переменные в шаблоне локальными? Как их тогда отличать от реально локальных переменных в шаблоне? Я собственно так и привык ориентироваться? $this->x — параметр из контроллера, $x — локальная переменная, созданная в шаблоне. А теперь будет каша и мешанина.

                              А в чем плюсы, я так и не понял (надеюсь, что мы не считаем плюсом то, что нужно вводить на 7 символов меньше)?
                                +1
                                А их действительно нужно для чего-то отличать?

                                7 символов по 50 раз в шаблоне — явный плюс. Меньше визуального шума.
                                  –1
                                  Подсчет символов в коде — это последнее, что надо делать. Что касается 50 раз, то слабо себе представляю, где столько раз нужно обращаться к параметрам из одного шаблона. Чаще это наоборот 5—10 раз.

                                  А по поводу необходимости отличия тут примерно то же самое, как и в случае отличия полей класса от локальных переменных метода. По сути — одно и то же.
                                  0
                                  Зачем? В виде должна быть логика представления, там вообще php кода должно быть по минимуму. Мне кажется, так гораздо лучше. Верстальщик опять же откроет вид или шаблон, и быстрее в него «въедет». И вообще есть такая штука, как ViewModel, в которой должны лежать подготовленные для вида данные.
                                    –2
                                    В виде должна быть логика представления (если это не Hello World). PHP-код — это как раз и есть логика представления. И ее должно быть ровно столько, сколько нужно. А верстальщики вроде должны шаблоны без логики делать, логика — задача программиста. Правда последнее утверждение может быть весьма спорным и наверняка найдутся куча примеров, когда программисты верстают или верстальщики пишут PHP-код в шаблонах.

                                    Зачем разделять локальные и глобальные переменные в шаблоне я написал выше.
                                    +1
                                    По идее, в шаблоне не должно быть локальных переменных.
                                    Откуда они там возьмутся? Только из циклов. Вообщем, локальных переменных стоит избегать.
                                      –1
                                      По какой идеи?

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

                                      Что касается избегания, то это как минимум ничем не обосновано. Локальные переменные нужны как хотя бы потому, что они делают блоки кода чище.
                                        +3
                                        «А вообще, в шаблоне могут быть вычисления (которые связаны с логикой представления)»

                                        Та нет же, любые вычисления — это уже не представление. Их нужно выносить в хэлперы.
                                          –3
                                          А это утверждение на чем основано? Хэлперы вообще-то служат не для хранения кода, а для его повторного использования.
                                            0
                                            Все утверждения основаны на опыте и здравом смысле.

                                            Если есть догма «хэлперы для повторного использования» то не верьте ей. Используйте их там где это необходимо. Переносить логику в шаблоны необходимости нет. Точно так же, как сейчас не принято писать яваскрипт в шаблонах, или пардон, SQL-запросы, точно так же, следует выводить любую логику за рамки html-кода. Если так не делать, до говнокода останется всего полшага.
                                              –4
                                              чтд…
                                                0
                                                А это условие считается логикой?

                                                if (!empty($entries)):
                                                foreach ($entries as $item):

                                                endforeach;
                                                else:
                                                echo «no entries»;
                                                endif;
                                      0
                                      Классная статья, спасибо ;-)
                                      Чувствуете, что ZF стал более удобнее, «человечнее» что-ли?
                                      Такой вопрос, в первом ZF был большой оверхед на Zend_Application. Во втором вы случаем не тестировали Zend\Mvc\Application?
                                        0
                                        Тестировать не тестировали. Но много где написано, что они все это дело переписали с нуля. И причиной тому была низкая производительность.
                                        0
                                        Интересует вопрос — чем локальные переменные идеологически и практически лучше в виде? Поддержка шаблонизаторов и короткий вывод в голом PHP коде шаблона?

                                        То, что контроллер возвращает, а не сообщает, конечно, хорошо — тестировать гоораздо проще — сам понимаю. А сам способ использования такой чем лучше?
                                          +1
                                          Отвечу только с практической стороны, и это сугубо личная точка зрения.

                                          Во вью-шаблонах про поддержку и короткий вывод я с вами согласен.
                                          Добавлю:
                                          — чище код, его проще поддерживать
                                          — теперь хелперы сразу выделяются благодаря $this (в ZF1 мне эта каша хелперов и переменных просто кажется некрасивой)
                                          — опять таки меньше магических вызовов (мысли вслух: хотя хм-м-м, а как они массив из контроллера в локальные переменные перевели? опять таки какая-то магия. надо будет посмотреть как они это реализовали.)

                                          Вобщем во вью шаблонах это чисто эстетическое улучшение.

                                          Про контроллеры:
                                          — с тестированием абсолютно согласен
                                          — избыточная связанность действий контроллера со вью-классом исчезла (надо писать в какой-то $this->view-> и опять какая-то ненужная тормознутость в использовании магических методов, вобщем некрасиво)
                                          — они подготовили контроллеры к возможности навешивания событий к действиям контроллера через новый компонент EventManager (думаю это основная причина)
                                          — ну и чисто для удобства, теперь можно прозрачно вызвать внутри одного метода/действия получить для обработки массив данных от другого метода/действия этого же класса (иногда такое требовалось и приходилось создавать приватный метод, который потом использовался по отдельности в двух методах).
                                            +1
                                            Перевести массив в набор переменных можно функцией extract. Интересно другое, если возвращать из контроллера данніе через return, все равно довольно часто придется создавать массив, и возвращать уже его, так как количесто вередаваеміх во view переменніх может біть разное (например в режиме администратора передать доп данные во view)
                                              0
                                              Спасибо, про extract я совсем забыл )

                                              Скорее всего в вашем случае «в режиме администратора передать доп данные во view» можно будет повешать событие на контроллер через EventManager.

                                              Либо всегда передавать полный набор данных и во вью уже ограничивать вывод согласно правам доступа (в этом случае будьте аккуратны если пользуетесь AjaxContext'ом, а то все данные в json'е станут всем доступны).
                                          0
                                          Вроде как ещё обещали переработать механизм bootstrap'инга, потому что сейчас (ZF 1) bootstrap запускается для всех модулей.

                                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                          Самое читаемое