php Используем dependency injection и container
DESCRIPTION
Dependency Injection - базовые понятия, и использование DI в Symfony 2.Выступление на Минской встрече PHP разработчиков.TRANSCRIPT
![Page 1: PHP Используем Dependency Injection и Container](https://reader035.vdocuments.site/reader035/viewer/2022081508/557fbeced8b42a40118b4e02/html5/thumbnails/1.jpg)
План
PHP Используем Dependency Injectionи Container
• Что такое Dependency Injection (DI)?• Что такое Контейнер служб (контейнер внедрения
зависимости)?• Как пришли к понятию Dependency Injection?• Использование DI и Контейнера в Symfony 2.
![Page 2: PHP Используем Dependency Injection и Container](https://reader035.vdocuments.site/reader035/viewer/2022081508/557fbeced8b42a40118b4e02/html5/thumbnails/2.jpg)
Обо мне
Александр Неманов
https://www.facebook.com/alexander.nemanov
Skype: gftrades.support
![Page 3: PHP Используем Dependency Injection и Container](https://reader035.vdocuments.site/reader035/viewer/2022081508/557fbeced8b42a40118b4e02/html5/thumbnails/3.jpg)
DI - что это?
Внедрение зависимости (англ. Dependency injection) — процесс предоставления внешней зависимости программному компоненту. Является специфичной формой “Обращения контроля” (Inversion of control, IoC)
IoS - это важный принцип объектно-ориентированного программирования, используемый для уменьшения связанности в коде программы.• Модули верхнего уровня не должны зависеть от модулей нижнего уровня. Оба
должны зависеть от абстракции.• Абстракции не должны зависеть от деталей. Детали должны зависеть от
абстракций.
Корнями иерархий должны быть абстрактные классы, в то время как конкретные классы в этой роли выступать не должны. Абстрактные базовые классы должны беспокоиться об определении функциональности, но не о ее реализации.
Контейнер служб - это реализация принципа внедрения зависимости
[email protected] skype: gftrades.support
![Page 4: PHP Используем Dependency Injection и Container](https://reader035.vdocuments.site/reader035/viewer/2022081508/557fbeced8b42a40118b4e02/html5/thumbnails/4.jpg)
Покодируем. И это работает…
class Invoice{ public function createUserInvoice($user) { $order = new PayedOrder('paypal'); $orderId = $order->createOrder(); $pfdGenerator = new PDFGenerator(); $invoice = $pfdGenerator->generate($orderId); $mailer = new Mailer('sendmail'); $mailer->send($user, $invoice); }}
$invoice = new Invoice();$invoice->createUserInvoice('Alex');
[email protected] skype: gftrades.support
![Page 5: PHP Используем Dependency Injection и Container](https://reader035.vdocuments.site/reader035/viewer/2022081508/557fbeced8b42a40118b4e02/html5/thumbnails/5.jpg)
SOLID
(S) Single responsibility principle - Принцип единственности ответственности(O) The Open Closed Principle - Принцип открытости/закрытости(L) The Liskov Substitution Principle - Принцип замещения Лисков(I) Interface segregation - Принцип разделения интерфейса(D) Dependency inversion - Принцип инверсии зависимости
[email protected] skype: gftrades.support
![Page 6: PHP Используем Dependency Injection и Container](https://reader035.vdocuments.site/reader035/viewer/2022081508/557fbeced8b42a40118b4e02/html5/thumbnails/6.jpg)
Строки которые сведут с ума
class Invoice{ public function createUserInvoice($user) { $order = new PayedOrder('paypal'); $orderId = $order->createOrder(); $pfdGenerator = new PDFGenerator(); $invoice = $pfdGenerator->generate($orderId); $mailer = new Mailer('sendmail'); $mailer->send($user, $invoice); }}
[email protected] skype: gftrades.support
![Page 7: PHP Используем Dependency Injection и Container](https://reader035.vdocuments.site/reader035/viewer/2022081508/557fbeced8b42a40118b4e02/html5/thumbnails/7.jpg)
Для теста немного “подшаманим”(принцип открытости/закрытости)
class Invoice{ public function createUserInvoice($user) { $order = new PayedOrder('paypal'); $orderId = $order->createOrder(); $pfdGenerator = new PDFGenerator(); $invoice = $pfdGenerator->generate($orderId); // TODO: Не забудь на проде раскоменьтить, а то будет как всегда!!! /* $mailer = new Mailer('sendmail'); $mailer->send($user, $invoice); */ }}
[email protected] skype: gftrades.support
![Page 8: PHP Используем Dependency Injection и Container](https://reader035.vdocuments.site/reader035/viewer/2022081508/557fbeced8b42a40118b4e02/html5/thumbnails/8.jpg)
Рефакторим на пути к DI
class Invoice{ private $order, $generator, $mailer; public function __construct(PayedOrder $order, PDFGenerator $generator, Mailer $mailer) { $this->order = $order; $this->generator = $generator; $this->mailer = $mailer; } public function createUserInvoice($user) { $orderId = $this->order->createOrder(); $invoice = $this->generator->generate($orderId); $this->mailer->send($user, $invoice); }}
$order = new PayedOrder('paypal');$pfdGenerator = new PDFGenerator();$mailer = new Mailer('sendmail');
$invoice = new Invoice($order, $pfdGenerator, $mailer);$invoice->createUserInvoice('Alex');
[email protected] skype: gftrades.support
![Page 9: PHP Используем Dependency Injection и Container](https://reader035.vdocuments.site/reader035/viewer/2022081508/557fbeced8b42a40118b4e02/html5/thumbnails/9.jpg)
Что мы еще можем сделать?class Invoice{ private $order, $generator, $mailer; public function __construct(PayedOrder $order, PDFGenerator $generator, Mailer $mailer) { $this->order = $order; $this->generator = $generator; $this->mailer = $mailer; } public function createUserInvoice($user) { $orderId = $this->order->createOrder(); $invoice = $this->generator->generate($orderId); $this->mailer->send($user, $invoice); }}
$order = new PayedOrder('paypal');$pfdGenerator = new PDFGenerator();$mailer = new Mailer('sendmail');
$invoice = new Invoice($order, $pfdGenerator, $mailer);$invoice->createUserInvoice('Alex');
[email protected] skype: gftrades.support
![Page 10: PHP Используем Dependency Injection и Container](https://reader035.vdocuments.site/reader035/viewer/2022081508/557fbeced8b42a40118b4e02/html5/thumbnails/10.jpg)
Используем Dependency Injection Container (DIC) (Рискнем!)
Используем Dependency Injection
Container (DIC) (Рискнем!)
[email protected] skype: gftrades.support
![Page 11: PHP Используем Dependency Injection и Container](https://reader035.vdocuments.site/reader035/viewer/2022081508/557fbeced8b42a40118b4e02/html5/thumbnails/11.jpg)
Реализуем свой, простой DIC
[email protected] skype: gftrades.support
class Container { protected $s=array(); function __set($k, $c) { $this->s[$k] = $c; } function __get($k) { return $this->s[$k]($this); }}
![Page 12: PHP Используем Dependency Injection и Container](https://reader035.vdocuments.site/reader035/viewer/2022081508/557fbeced8b42a40118b4e02/html5/thumbnails/12.jpg)
Используем
$c = new Container();$c->payment_system = function ($c) { return 'paypal'; };$c->order = function ($c) { return new PayedOrder($c->payment_system);};$c->pfdGenerator = function ($c) { return new PDFGenerator();};$c->mailer_transport = function ($c) { return 'sendmail';};$c->mailer = function ($c) { return new Mialer($c->mailer_transport);};$c->invoice = function ($c) { return new Invoice($c->order, $c->pfdGenerator, $c->mailer);};
$invoice = $c->invoice;$invoice->createUserInvoice('Alex');
[email protected] skype: gftrades.support
![Page 13: PHP Используем Dependency Injection и Container](https://reader035.vdocuments.site/reader035/viewer/2022081508/557fbeced8b42a40118b4e02/html5/thumbnails/13.jpg)
Symfony DI
Контейнер служб (или же контейнер внедрения зависимости) - это также PHP объект, который управляет созданием служб (т.е. объектов).
[email protected] skype: gftrades.support
![Page 14: PHP Используем Dependency Injection и Container](https://reader035.vdocuments.site/reader035/viewer/2022081508/557fbeced8b42a40118b4e02/html5/thumbnails/14.jpg)
Symfony DIC
composer.json{ "require": { "symfony/dependency-injection": "v2.3.0", "symfony/yaml": "v2.3.0", "symfony/config": "v2.3.0", }}
[email protected] skype: gftrades.support
![Page 15: PHP Используем Dependency Injection и Container](https://reader035.vdocuments.site/reader035/viewer/2022081508/557fbeced8b42a40118b4e02/html5/thumbnails/15.jpg)
Symfony DICservices.ymlparameters: payment.type: paypal mailer.transport: sendmail services: order: class: PayedOrder arguments: [%payment.type%] generator_pdf: class: PDFGenerator mailer: class: Mailer arguments: [%mailer.transport%] invoice: class: Invoice arguments: [@order, @generator_pdf, @mailer]
[email protected] skype: gftrades.support
![Page 16: PHP Используем Dependency Injection и Container](https://reader035.vdocuments.site/reader035/viewer/2022081508/557fbeced8b42a40118b4e02/html5/thumbnails/16.jpg)
Symfony DIC
// index.phpuse Symfony\Component\DependencyInjection\ContainerBuilder;use Symfony\Component\Config\FileLocator;use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
$container = new ContainerBuilder();$loader = new YamlFileLoader($container, new FileLocator(__DIR__));$loader->load('services.yml');
$invoice = $container->get('invoice');$invoice->createUserInvoice('Alex');
[email protected] skype: gftrades.support
![Page 17: PHP Используем Dependency Injection и Container](https://reader035.vdocuments.site/reader035/viewer/2022081508/557fbeced8b42a40118b4e02/html5/thumbnails/17.jpg)
Symfony DI
• Параметры службы• Массивы параметров• Импорт конфигурации• Использование одних служб внутри других• Опциональные зависимости• constructor injection, setter injection, property injection• Опциональные ссылки на службы• Основные службы Symfony и службы от сторонних
разработчиков (session, templating, mailer, request)• Разные конфиги для разных окружений (prod, dev,
test)[email protected] skype: gftrades.support
![Page 18: PHP Используем Dependency Injection и Container](https://reader035.vdocuments.site/reader035/viewer/2022081508/557fbeced8b42a40118b4e02/html5/thumbnails/18.jpg)
SF DI - продвинутая конфигурация
• Публичные и приватные службы• Псевдонимы (alias)• Таги (tags) templating.helper, twig.extension...
[email protected] skype: gftrades.support
![Page 19: PHP Используем Dependency Injection и Container](https://reader035.vdocuments.site/reader035/viewer/2022081508/557fbeced8b42a40118b4e02/html5/thumbnails/19.jpg)
Фреймворки использующие DIC
Реализация внедрения зависимостей PHP5• DiContainer• Garden• Xyster Framework• Lion Framework• TYPO3 Flow• Symfony 2 Dependency Injection• Zend Framework 2• Laravel's IoC Container
[email protected] skype: gftrades.support
![Page 20: PHP Используем Dependency Injection и Container](https://reader035.vdocuments.site/reader035/viewer/2022081508/557fbeced8b42a40118b4e02/html5/thumbnails/20.jpg)
To be, or not to be: that is the question
Используйте мудро, но
[email protected] skype: gftrades.support
![Page 21: PHP Используем Dependency Injection и Container](https://reader035.vdocuments.site/reader035/viewer/2022081508/557fbeced8b42a40118b4e02/html5/thumbnails/21.jpg)
DI это требование, если вы используете TDD
Сильная связанность затрудняет тестирование
Работа с внешними ресурсами затрудняет тестированиеПример внешних ресурсов:• Обращение к сторонним сервисам• Файловая система• Файлы конфигурации• …
[email protected] skype: gftrades.support
![Page 22: PHP Используем Dependency Injection и Container](https://reader035.vdocuments.site/reader035/viewer/2022081508/557fbeced8b42a40118b4e02/html5/thumbnails/22.jpg)
Почему мы используем DI
• Late Binding - сервисы могут быть заменены другими сервисами
• Extensibility - код может быть легко расширен и повторно использован
• Parallel development - разработка кода с низкой связанностью упрощает командную параллельную разработку
• Maintainability - классы с четкими границами легко сопровождать
• Testability - модули могут быть протестированы
[email protected] skype: gftrades.support