понедельник, 26 декабря 2011 г.

Meet Zend Framework 2.0.0

                             Meet Zend Framework 2.0.0
                                                       join free or die hard
Многие, скорее всего, слышали о ZendFrameworke ( если нет – не стоит разбивать мне сердце такими заявлениями, прочитайте статью хотя бы для расширения кругозора), но не все еще знакомы с новеньким релизом 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
Место ZF среди собратьев
Zend Framework Webinars
Простой пример использования RESTful web-service using ZF2.
Мнение эксперта Мартина Фаулера о DI
  ·  Все компоненты фреймворка построены на объектно-ориентированном PHP 5 и являются E_STRICT совместимыми;

 · Use-at-will архитектура с использованием минимальных зависимостей;

   · Расширяемая реализация MVC, по умолчанию поддерживающая лэйауты и шаблоны вида;

  ·  Поддержка различных систем баз данных и вендоров, включая 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(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);
}

Проблема 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

 В новом релизе 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 ).