PHP Используем Dependency Injection и Container

6,590 views

Published on

Dependency Injection - базовые понятия, и использование DI в Symfony 2.Выступление на Минской встрече PHP разработчиков.

Published in: Technology

PHP Используем Dependency Injection и Container

  1. 1. План PHP Используем Dependency Injection и Container • Что такое Dependency Injection (DI)? • Что такое Контейнер служб (контейнер внедрения зависимости)? • Как пришли к понятию Dependency Injection? • Использование DI и Контейнера в Symfony 2.
  2. 2. Обо мне Александр Неманов https://www.facebook.com/alexander.nemanov bug@tut.by Skype: gftrades.support
  3. 3. DI - что это? Внедрение зависимости (англ. Dependency injection) — процесс предоставления внешней зависимости программному компоненту. Является специфичной формой “Обращения контроля” (Inversion of control, IoC) IoS - это важный принцип объектно-ориентированного программирования, используемый для уменьшения связанности в коде программы. • Модули верхнего уровня не должны зависеть от модулей нижнего уровня. Оба должны зависеть от абстракции. • Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций. Корнями иерархий должны быть абстрактные классы, в то время как конкретные классы в этой роли выступать не должны. Абстрактные базовые классы должны беспокоиться об определении функциональности, но не о ее реализации. Контейнер служб - это реализация принципа внедрения зависимости bug@tut.by skype: gftrades.support
  4. 4. Покодируем. И это работает… 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'); bug@tut.by skype: gftrades.support
  5. 5. SOLID (S) Single responsibility principle - Принцип единственности ответственности (O) The Open Closed Principle - Принцип открытости/закрытости (L) The Liskov Substitution Principle - Принцип замещения Лисков (I) Interface segregation - Принцип разделения интерфейса (D) Dependency inversion - Принцип инверсии зависимости bug@tut.by skype: gftrades.support
  6. 6. Строки которые сведут с ума 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); } } bug@tut.by skype: gftrades.support
  7. 7. Для теста немного “подшаманим” (принцип открытости/закрытости) 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); */ } } bug@tut.by skype: gftrades.support
  8. 8. Рефакторим на пути к 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'); bug@tut.by skype: gftrades.support
  9. 9. Что мы еще можем сделать? 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'); bug@tut.by skype: gftrades.support
  10. 10. Используем Dependency Injection Container (DIC) (Рискнем!) Используем Dependency Injection Container (DIC) (Рискнем!) bug@tut.by skype: gftrades.support
  11. 11. Реализуем свой, простой DIC bug@tut.by skype: gftrades.support class Container { protected $s=array(); function __set($k, $c) { $this->s[$k] = $c; } function __get($k) { return $this->s[$k]($this); } }
  12. 12. Используем $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'); bug@tut.by skype: gftrades.support
  13. 13. Symfony DI Контейнер служб (или же контейнер внедрения зависимости) - это также PHP объект, который управляет созданием служб (т.е. объектов). bug@tut.by skype: gftrades.support
  14. 14. Symfony DIC composer.json { "require": { "symfony/dependency-injection": "v2.3.0", "symfony/yaml": "v2.3.0", "symfony/config": "v2.3.0", } } bug@tut.by skype: gftrades.support
  15. 15. Symfony DIC services.yml parameters: 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] bug@tut.by skype: gftrades.support
  16. 16. Symfony DIC // index.php use SymfonyComponentDependencyInjectionContainerBuilder; use SymfonyComponentConfigFileLocator; use SymfonyComponentDependencyInjectionLoaderYamlFileLoader; $container = new ContainerBuilder(); $loader = new YamlFileLoader($container, new FileLocator(__DIR__)); $loader->load('services.yml'); $invoice = $container->get('invoice'); $invoice->createUserInvoice('Alex'); bug@tut.by skype: gftrades.support
  17. 17. Symfony DI • Параметры службы • Массивы параметров • Импорт конфигурации • Использование одних служб внутри других • Опциональные зависимости • constructor injection, setter injection, property injection • Опциональные ссылки на службы • Основные службы Symfony и службы от сторонних разработчиков (session, templating, mailer, request) • Разные конфиги для разных окружений (prod, dev, test) bug@tut.by skype: gftrades.support
  18. 18. SF DI - продвинутая конфигурация • Публичные и приватные службы • Псевдонимы (alias) • Таги (tags) templating.helper, twig.extension... bug@tut.by skype: gftrades.support
  19. 19. Фреймворки использующие DIC Реализация внедрения зависимостей PHP5 • DiContainer • Garden • Xyster Framework • Lion Framework • TYPO3 Flow • Symfony 2 Dependency Injection • Zend Framework 2 • Laravel's IoC Container bug@tut.by skype: gftrades.support
  20. 20. To be, or not to be: that is the question Используйте мудро, но bug@tut.by skype: gftrades.support
  21. 21. DI это требование, если вы используете TDD Сильная связанность затрудняет тестирование Работа с внешними ресурсами затрудняет тестирование Пример внешних ресурсов: • Обращение к сторонним сервисам • Файловая система • Файлы конфигурации • … bug@tut.by skype: gftrades.support
  22. 22. Почему мы используем DI • Late Binding - сервисы могут быть заменены другими сервисами • Extensibility - код может быть легко расширен и повторно использован • Parallel development - разработка кода с низкой связанностью упрощает командную параллельную разработку • Maintainability - классы с четкими границами легко сопровождать • Testability - модули могут быть протестированы bug@tut.by skype: gftrades.support
  23. 23. Вопросы bug@tut.by skype: gftrades.support

×