Почему гениальном? Потому, что весь код этого творения укладывается в 80 строк – маленький объект с большими возможностями.
Контейнер представляет из себя один класс, и его подключение в проект выглядит следующим образом:
require_once '/path/to/Pimple.php';
Создание контейнера так же просто:
$container = new Pimple();
Как и многие другие DI контейнеры, Pimple поддерживает два вида данных: сервисы и параметры.
Объявление параметров
Объявить параметры в Pimple очень просто: используем контейнер как простой массив:
// Объявляем параметр $container['cookie_name'] = 'SESSION_ID'; $container['session_storage_class'] = 'SessionStorage';
Объявление сервисов
Сервис — некий объект, часть системы, которая выполняет свою конкретную задачу.
Например, сервисами могут являться: объект, предоставляющий соединение с базой данных, отвечающий за отправку почты, шаблонизацию выводимых данных и т.д.
В Pimple сервисы определяются как анонимные функции, возвращающие объект сервиса:
// Объявление сервисов $container['session_storage'] = function ($c) { return new $c['session_storage_class']($c['cookie_name']); }; $container['session'] = function ($c) { return new Session($c['session_storage']); };
Обратите внимание, что анонимная функция имеет доступ к текущему контейнеру и это позволяет использовать в ней другие параметры или сервисы.
Объекты сервиса создаются только при обращении к ним, так что порядок объявления не имеет никакого значения.
Пользоваться созданными сервисами так же просто:
// Получение объекта сервиса $session = $container['session']; // Предыдущая строка равносильна следующему коду // $storage = new SessionStorage('SESSION_ID'); // $session = new Session($storage);
Объявление сервисов «Синглтонов»
По умолчанию при каждом вызове Pimple возвращает новый объект сервиса. Если же требуется один экземпляр на всё приложение, всё, что вам необходимо сделать – обернуть объявление в метод share():
$container['session'] = $container->share(function ($c) { return new Session($c['session_storage']); });
Объявление функций
Так как Pimple рассматривает все анонимные функции как объявление сервисов, то для объявления именно функций в контейнере необходимо лишь обернуть всё это дело в метод protect():
$container['random'] = $container->protect(function () { return rand(); });
Изменение сервисов после их объявления
В некоторых случаях может понадобиться изменение поведения уже объявленного сервиса. Тогда можно использовать метод extend() для регистрации дополнительного кода, который будет выполнен сразу же после создания сервиса:
$container['mail'] = function ($c) { return new \Zend_Mail(); }; $container['mail'] = $container->extend('mail', function($mail, $c) { $mail->setFrom($c['mail.default_from']); return $mail; });
Первым параметром в данную функцию передается имя сервиса, которое нужно дополнить, а вторым – функция, принимающая в качестве аргументов объект сервиса и текущий контейнер. В итоге при обращении к сервису получается объект, возвращаемый данной функцией.
Если же сервис был «Синглтоном», необходимо повторно обернуть код дополнения сервиса методом share(), иначе дополнения будут вызываться каждый раз при обращении к сервису:
$container['twig'] = $container->share(function ($c) { return new Twig_Environment($c['twig.loader'], $c['twig.options']); }); $container['twig'] = $container->share($container->extend('twig', function ($twig, $c) { $twig->addExtension(new MyTwigExtension()); return $twig; }));
Доступ к функции, возвращающей сервис
Каждый раз, когда вы обращаетесь к сервису, Pimple автоматически вызывает функцию его объявления. Если же требуется получить прямой доступ именно к функции объявления, можно использовать метод raw():
$container['session'] = $container->share(function ($c) { return new Session($c['session_storage']); }); $sessionFunction = $container->raw('session');
Повторное использование готового контейнера
Если вы от проекта к проекту используете одни и те же библиотеки, вы можете создать готовые контейнеры для повторного использования. Всё, что нужно сделать – это расширить класс Pimple:
class SomeContainer extends Pimple { public function __construct() { $this['parameter'] = 'foo'; $this['object'] = function () { return stdClass(); }; } }
И вы можете с лёгкостью использовать данный готовый контейнер внутри другого контейнера:
$container = new Pimple(); // Объявление сервисов и параметров основного контейнера // ... // Вставка другого контейнера $container['embedded'] = $container->share(function () { return new SomeContainer(); }); // Конфигурация встроенного контейнера $container['embedded']['parameter'] = 'bar'; // И его использование $container['embedded']['object']->...;
Заключение
Управление зависимостями — одна из важнейших и в то же время трудных задач в разработке веб-приложений. Большинство фреймворков предлагают собственные решения данной проблемы. Однако в случае использования фреймворков без менеджера зависимостей или проектирования архитектуры приложения без фреймворков, в качестве DI контейнера я бы однозначно выбрал Pimple.
P.S. Примеры использования — перевод официального readme Pimple.
ссылка на оригинал статьи http://habrahabr.ru/post/199296/
Добавить комментарий