Meet Zend Framework 2.0.0
join free or die hard
Многие, скорее всего, слышали о ZendFramework’e ( если нет – не стоит разбивать мне сердце такими заявлениями, прочитайте статью хотя бы для расширения кругозора), но не все еще знакомы с новеньким релизом ZendFramework 2.0.0.beta1. Предлагаю прочитать подобранный мной материал, дабы преодолеть все барьеры на пути к новой версии ZendFramework(далее ZF).
Последняя стабильная версия ZF 1.11 включает следующие фичи (и не только):
Tips немного истории: Окт, 2005 – анонс и начало работы над ZF1 Март, 2006 – релиз первой версии ZF 0.1.0 Фев, 2010 – начата работа над ZF2.0 Окт, 2011 – первый бета- релиз ZF2.0.0 требования ZendFramework2.0.0.beta1: - PHP 5.3.3 (или выше); - веб-сервер с поддержкой mod_rewrite или похожей функциональности. откуда скачать: есть ли жизнь после beta1, или как обстоят дела с релизами релизы обещают раз в 6 недель максимум get involved: Official page of ZF modules Official Github of ZF 2 Zend Framework Webinars 15 примеров использования Zend\Di by Ralph Schindler Мнение эксперта Мартина Фаулера о DI |
· Все компоненты фреймворка построены на объектно-ориентированном PHP 5 и являются E_STRICT совместимыми;
· Поддержка различных систем баз данных и вендоров, включая MariaDB, MySQL, Oracle, IBMDB2, MicrosoftSQLServer, PostgreSQL, SQLite и InformixDynamicServer ;
· Возможность составления и рассылки писем эл. почты(email), доступная через mbox, Maildir, POP3 и IMAP4;
· Гибкое кеширование подсистем через поддержку различных типов бэкенда, таких как memory или filesystem.
Несмотря на сильные стороны фреймворка, искушенные программисты быстро выявили недостатки ZF 1, к которым они отнесли:
Обилие Singleton’ов, обоснованных тем, что в системе должно существовать не более одного экземпляра заданного класса(Zend/Controller/Front). Кроме того, такой подход обеспечивает простой доступ к глобальным данным и/или функциям. С другой стороны, Синглтоны ведут к увеличению числа скрытых зависимостей, и, как одно из следствий, к сложному тестированию. Ко всему прочему, доступ к Singleton’у в мультипоточном контексте должен быть сериализован, например, залочиванием(а есть еще такое понятие как Double Check Locking….).
Hard-coded зависимости, которые в преставлении не нуждаются.
Низкую производительность, вызванную, в основном, постоянным поиском по файловой системе(следствие множественного использования require_once). Наглядный пример: затратный Bootsrap.
Слабую реализацию модулей: возможности повторного использования ограничены, отсутствует механизм распределения и управления зависимостями.
Менее важная проблема, но все же актуальна для тех, кто не жалеет сил времени, и стремится внести доработки любимого фреймворка: многолетняя текучка с предложениями, сложности с лицензией Contributor License Agreement(CLA) и проч.
Очевидно, душа пхп-разработчика хотела большего и получила удовлетворение с появлением ZF 2 и его замечательных нововведений, соответствующих девизу “Focus on consistency and performance”.
Если кратко, изменения, произведенные в релизе, включили удаление require_once statements, применение фич PHP 5.3(например, переход на неймспейсы), переписанный Zend\Session и другие классы, ранее реализованные по Black Box дизайну, усложнявшему тестирование. Дополнительные изменения включают сокращение зависимости от магических методов(__call()), уменьшение количества использований Singleton’ов и модульную структуру Zend\Application. Обсуждение требований к MVC-инфраструктуре следующей версии фреймворка можно найти здесь. Кроме того, разработчики Zend утверждают, что участие в разработке исходного кода теперь упрощено.
Если не очень кратко, о новых возможностях ZF 2 можно почитать ниже.
- Производительность увеличилась благодаря удалению require_once statements и добавлению набора загрузчиков:
- fallback-автолоадинг для быстрой разработки
require_once ‘Zend/Loader/StandartAutoloader.php’; $loader = new Zend\Loader\StandartAutoloader(array( ‘fallback_autoloader’ => true, )); |
- namespace prefix autoloader для обычного кода
return array( ‘My\Foo\Bar’ => __DIR__ . ‘/Foo/Bar.php’, ); |
- classmap_generator, где возможно. Для минимизации сопутствующей работы над поддержкой карты классов, реализован инструмент(bin/classmap_generator.php). Пример генерации тривиален:
prompt >> cd your/library prompt >> php path/to/classmap_generator.php –w # Class Map now exists in .classmap.php |
С разными подходами приходит необходимость в фабрике, которая содержит информацию о доступных загрузчиках, представленных выше, и их конфигурации. В ZF 2 эту роль выполняет AutoloaderFactory.
Пока неясно насколько − или во сколько раз − производительность стала лучше. Наиболее встречаемый вариант касательно данного вопроса – «Now application works very very fast. No, really!». Скорее всего, реальные данные появятся ближе к релизу стабильной версии.
- Поднеймспейс \Exception для работы с исключениями ( взамен теперь уже ликвидированного Zend_Exception ). Новая система позволяет перехватывать Exception’ы специальных и базовых типов и компонент, SPL Exception’ы. Каждый компонент определяет Exception interface:
namespace Zend\EventManager; interface Exception {} |
namespace Zend\EventManager\Exception; use Zend\EventManager\Exception; class InvalidDigitException{ extends \ InvalidDigitException; implements Exception; } |
- EventManager(Zend\EventManager)
EventManager(EM) является очень важным компонентом, т.к. его архитектура позволяет легко изменить логику частей приложения(например, добавить дополнительный код до/после выполнения модуля).
Он построен на основе аспектно-ориентированного дизайна, в котором код определяет некоторые аспекты(логически законченные участок кода), интересующие разработчика как субъект наблюдения. Другой код выполняется, когда аспект запущен. В качестве инструмента в ZF 2 реализован subject/observer паттерн.
В EM также реализована событийно-ориентированая архитектура(event-driven). Событие представляет собой объект, содержащий данные, когда и как он был инициирован: какой объект его вызвал, переданные параметры и т.п. Событие имеет имя, что позволяет привязывать обработчики к определенному событию, ссылаясь на имя этого события. На настоящий момент такая архитектура уже используется в Zend/Module, Zend/MVC, Zend/Session. Пример использования в Zend\MVC\Application:
protected function attachDefaultListeners() { $events = $this->events; $events->attach(‘route’, array($this, ‘route’)); $events->attach(‘dispatch’, array($this, ‘dispatch’)); } |
Набор джентльмена для работы со всем этим должен включать как минимум:
- экземпляр класса EventManager;
- один и более обработчик событий, привязанный к одному или нескольким событиям;
- вызов EventManager::trigger() для инициации обработки события.
EventManager feat. EventCollection
Один из принципов, которым стараются следовать в ZF2 − это Принцип подстановки Лисков. Интерпретацией этого принципа может быть следующее: для любого класса, который в будущем может понадобиться переопределить другим классом, должен быть определен “базовый” интерфейс. И это позволяет разработчикам использовать другую реализацию какого-то класса, определив методы этого интерфейса. Поэтому был разработан интерфейс EventCollection, который описывает объект, способный к агрегации слушателей на события, и инициации этих событий. Стандартная реализация EventManager которая вошла в ZF2 представлена ниже:
interface EventCollection { public function trigger($event, $target = null, $argv = array(), $callback = null); public function triggerUntil($event, $target, $argv = null, $callback = null); public function attach($event, $callback, $priority = 1); public function detach(CallbackHandler $listener); public function getEvents(); public function getListeners($event); public function clearListeners($event); } |
- Dependency Injection(Zend\Di)
Проблема hard-coded зависимостей в ZF2 решается с помощью методики инверсии зависимостей (Dependency Inversion, далее DI). Зависимости между классами превращаются в ассоциации между объектами, которые в свою очередь, могут устанавливаться и меняться во время выполнения приложения. Таким образом, компоненты приложения становятся менее связанными между собой. Благодаря этому повышается возможность повторного использования кода и его мобильность. Для отображения отношений зависимостей между объектами используется объектный граф Dependency Injection Container.
Иньекции передаются в код двумя способами(они не исключают друг друга):
Иньекции передаются в код двумя способами(они не исключают друг друга):
- Constructor Injection (через параметры конструктора)
Инъекция с помощью конструктора использует конструктор для ассоциирования объекта с конкретными реализациями абстракций. При использовании этого типа инверсии зависимостей, необходимые объекты передаются в конструктор в качестве аргументов.
- Setter Injection(через методы)
Инъекция при помощи set-метода требует определения отдельного set-метода для каждого из инъецируемых объектов. От предыдущего типа инъекции она отличается местом инъецирования(«впрыскивания»).
Построение операций осуществляются тремя возможными путями:
1. Во время выполнения( по требованию);
2. Компиляция (формируется массив DIArrayDefenition);
3. Вручную с помощью классов ClassDefinition, BuliderDefention.
Пример использования DI в Zend\Mvc\Bootstrap
class Bootstrap implements Bootstrapper { …. // Sets up the locator based on the configuration provided protected function setupLocator(AppContext $application) { $di = new Di; $di->instanceManager()->addTypePreference('Zend\Di\Locator', $di); $config = new DiConfiguration($this->config->di); $config->configure($di); $application->setLocator($di); } } |
- RestfulController
В ZF 1 классы Zend_Rest_Server и Zend_Rest_Client реализуют взаимодействие на основе протокола XML-RPC (существует единая точка входа, URI отсутствуют, метод передается в виде параметра "method"). Те, кто знаком с REST-архитектурой, понял, что о ней здесь речь не идет. Проблему решили в ZF2 добавлением RestfulController, который следует правилам построения архитектуры REST. Он разбирает URI, определяя, какой тип запроса пришел, и обрабатывает запрос в зависимости от этого. Ниже представлена сводная таблица методов и соответствующих ответов сервера:
Метод передачи сообщения через HTTP-протокол | Метод RestfulController’a | Код ответа |
GET | getList() или get()– если передан id. | |
POST | create() ожидает данные, как правило, с суперглобального массива $_POST. | 201 |
PUT | update() обязательный параметр id | 200, 202 |
DELETE | delete() обязательный параметр id | 200, 204 |
- Модули (Zend\Module)
В новом релизе ZF осуществляется полная поддержка модулей. Наконец, к ним применимы прилагательные «автономный», «переносимый» «готов к использованию». Портативность происходит по средствам phar-packaing. Производительность достигается кешированием. Осуществлено управление зависимостями как между модулями и версиями php, так и между несколькими модулями с помощью Dependency Manager.
В ZF 2 модуль – это просто неймспейс директория с одиночным классом Module.php в ней; ни больше, ни меньше. Структура простейшего модуля выглядит так:
~modules ~MyModule ~Module.php |
Содержимое файла Module.php:
<?php namespace MyModule class Module { /* */ } |
Важные замечания о структуре папок и расположении фалов:
- параметры конфигурации подгружается функцией getConfig() из папки /modules/ MyModule/ configs;
- css, js и т.д. используют из папки /modules/ MyModule/ public;
- php код лежит в /modules/ MyModule/ src;
- Unit tests должны быть созданы в папке /modules/ MyModule/ tests.
На заметку: желтая IT-пресса пускает слухи о возможности портирования модулей между Symphony и ZF в будущем( что было бы неплохо ), благодаря их схожей структуре и реализации. Пока такой информации из официальных источников не поступало=)
Переход с ZF1->ZF2
Возможно, у тех, кто дочитал до этого места, возникли мысли: «Хорошо, я бы посмотрел(а) поближе на все эти нововведения, но разрабатываю/поддерживаю приложение на ZF 1. Есть ли возможность легко перевести его на ZF 2?». На настоящий момент это сделать несложно, т.к. все компоненты остались на месте; код контроллеров и шаблонов не сильно поменялся; самое сложное – внедрить NS (но при сильном желании можно автоматизировать этот процесс с помощью самописного скрипта) и перевести приложение на модульную структуру. С одной стороны, поговаривают, что дальнейшие изменения могут сильнее повлиять на переход. С другой стороны, есть информация о предоставлении специальных инструментов для перехода в будущем.
Над чем еще обещают поработать:
Локализация и интернационализация;
Тестирование;
Документация;
Инструменты перехода.
Несмотря на то, что положительные тенденции по облегчению работы сZF2(во многом благодаря использованию преимуществ php 5.3) уже видны невооруженным глазом, разработчики не торопятся опробовать новый бета-релиз в действии, настороженно приглядываясь к фичам ZF2 и ожидая более стабильной версии с сопутствующей документацией.
Автор: Анна Хабибуллина( twitter @_khabibullina ).