Desmistificando Injeção de Dependências

Desmistificando Injeção de Dependências

A injeção de dependências é uma ferramenta muito importante no desenvolvimento de software orientado a objetos. Porém, ainda pairam muitas dúvidas sobre o seu funcionamento e conceitos relacionados. Nesta palestra serão abordados os conceitos de injeção de dependência, inversão de controle e contêiner de injeção de dependência. Será apresentado o princípio da inversão de dependências e conceitos relacionados como autowire, resolução automática e binding. Será apresentada a PSR-11 e bibliotecas e ferramentas que tratam de contêineres de injeção de dependências. E, por fim, será disponbilizado um lista com referências para estudos.

52711e2157a6fed933b0361cc06a6953?s=128

Marcel dos Santos

April 24, 2019
Tweet

Transcript

  1. 3.
  2. 6.

    Interaja nas mídias sociais!
 
 - fale sobre o evento,

    palestrantes e conteúdo - tire fotos do evento e publique
 - interaja com outros participantes do evento - tire dúvidas ou dê feedbacks para os palestrantes
  3. 9.

    !// class with a dependency
 class Car { private $engine;

    public function !__construct() { $this!->engine = new Engine(); } public function start() { $this!->engine!->start(); !// engine is a dependency } }
  4. 10.

    um módulo A depende do módulo B quando qualquer código

    do módulo A referencia qualquer código do módulo B
  5. 11.

    a referência é feita ao chamar uma função, usar algum

    dado ou usar algum tipo definido no módulo A
  6. 15.

    !// class to create a User object
 class User {

    private $name; private $age; public function !__construct(string $name, int $age) { $this!->name = $name; $this!->age = $age; } public function sayName() : void { echo "Hello, my name is {$this!->name}!"; } }
  7. 16.

    !// two objects representing user abstractions
 $alice = new User('Alice',

    22); $bob = new User('Bob', 27); $alice!->sayName(); !// Hello, my name is Alice! $bob!->sayName(); !// Hello, my name is Bob!
  8. 17.

    !// current state of $alice object
 var_dump($alice); !/* class User#3

    (2) { private $name !=> string(5) "Alice" private $age !=> int(22) } !*/
  9. 20.

    !// not cohesive class
 class Cart { private $items; public

    function !__construct() { $this!->items = []; } public function numberOfItems() : int { return count($this!->items); } public function calculateDeliveryPrice() : float { !// calculates the delivery price } }
  10. 22.

    o acoplamento ocorre quando o código de um módulo utiliza

    código de outro módulo, seja ao chamar uma função ou acessar algum dado
  11. 23.

    !// class Car is coupled to Engine class
 class Car

    { private $engine; public function !__construct() { $this!->engine = new Engine(); } public function start() { $this!->engine!->start(); !// engine is a dependency } }
  12. 30.

    a injeção de dependências pode ser feita através de um

    parâmetro do construtor ou utilizando um método setter
  13. 31.

    !// dependency injection via constructor
 class Car { private $engine;

    public function !__construct(Engine $engine) { $this!->engine = $engine; } public function start() { $this!->engine!->start(); } }
  14. 32.

    !// injecting the dependency
 $engine = new Engine(); $car =

    new Car($engine); $car!->start(); !// Starting the engine
  15. 34.

    !// coupling your object construction with !// the construction of

    its dependencies
 class Car { private $engine; public function !__construct() { $this!->engine = new Engine; } public function start() { $this!->engine!->start(); } }
  16. 40.

    3. módulos de baixo nível também devem
 depender de abstrações

    2. módulos de alto nível devem depender 
 de abstrações e não de implementações 1. módulos de alto nível não devem 
 depender de módulos de baixo nível o princípio de inversão de dependência diz:
  17. 42.

    !// concrete implementation in order to get coordinates !// from

    address in Google Maps and OpenStreetMap class GoogleMaps { public function getCoordinatesFromAddress($address) { !// calls Google Maps webservice } } class OpenStreetMap { public function getCoordinatesFromAddress($address) { !// calls OpenStreetMap webservice } }
  18. 43.

    !// class StoreService depends on a concrete implementation !// of

    GoogleMaps geolocation service class StoreService { public function getStoreCoordinates($store) { $geolocationService = new GoogleMaps(); return $geolocationService !->getCoordinatesFromAddress($store!->getAddress()); } }
  19. 46.

    !// geolocation services abstraction (contract) !// each concrete implementation must

    follow this contract interface GeolocationService { public function getCoordinatesFromAddress($address); }
  20. 47.

    !// concrete implementation must follow the contract class GoogleMaps implements

    GeolocationService { public function getCoordinatesFromAddress($address) { !// calls Google Maps webservice } } class OpenStreetMap implements GeolocationService { public function getCoordinatesFromAddress($address) { !// calls OpenStreetMap webservice } }
  21. 48.

    !// the class should depends on abstraction (GeolocationService) class StoreService

    { private $geolocationService; public function !__construct(GeolocationService $geolocationService) { $this!->geolocationService = $geolocationService; } public function getStoreCoordinates($store) { return $this!->geolocationService !->getCoordinatesFromAddress($store!->getAddress()); } }
  22. 52.

    a inversão de controle é sobre deixar de ir atrás

    das dependências e deixar que elas sejam levadas até você
  23. 57.

    !// dependency injection is possible without libraries
 $geolocationService = new

    GoogleMaps(); $storeService = new StoreService($geolocationService);
  24. 59.

    utilizar injeção de dependências auxilia nos testes unitários pois tornam

    as classes fracamente acopladas, altamente coesas e facilita o mocking de objetos
  25. 61.

    a injeção de dependências é uma boa prática, mas torna

    o processo de instanciação mais complicado
  26. 62.

    !// complex instantiation process
 $handler = new StreamHandler(!__DIR!__ . '/email.log');

    $logger = new Logger('main', [$handler]); $mailer = new Mailer($logger); $notifier = new UserNotifier($mailer);
  27. 64.

    o processo de instanciação de objetos se torna mais fácil

    ao utilizar um contêiner de injeção de dependência
  28. 66.

    um contêiner de injeção de dependências é um mapa das

    dependências que a sua classe necessita e com a lógica para criar essas dependências
  29. 67.

    um contêiner de injeção de dependências descreve objetos e suas

    dependências e instancia e configura os objetos sob demanda
  30. 69.

    !// config to inject a GoogleMaps instance when using 


    !// GeolocationService type hint
 $container!->set('GeolocationService', \DI\create(‘GoogleMaps'));
  31. 71.

    !// config to inject a GoogleMaps instance when using 


    !// GeolocationService type hint (Laravel)
 $this!->app!->bind( 'App\Services\GeolocationService', 'App\Services\GoogleMaps' );
  32. 72.

    um contêiner de injeção de dependências é conhecido também como

    service container, IOC container ou dependency injection container (DIC)
  33. 74.

    class UserManager { private $mailer; public function !__construct(Mailer $mailer) {

    $this!->mailer = $mailer; } public function register($email, $password) { !// The user just registered, we create his account !// !!... $this!->mailer!->mail($email, 'Hello and welcome!'); } }
  34. 75.
  35. 76.

    !// get a UserManager object from container, the !// dependencies

    are resolved automatically
 $userManager = $container!->get('UserManager');
  36. 77.

    !// get a UserManager object from container, the !// dependencies

    are resolved automatically (Laravel) 
 $userManager = $this!->app!->make('UserManager');
  37. 78.

    o contêiner utiliza uma técnica chamada autowiring para analisar as

    dependências e criá-las conforme necessário
  38. 82.

    reflection é a capacidade de um programa inspecionar ele mesmo

    e modificar a sua lógica em tempo de execução
  39. 83.

    reflection é perguntar a um objeto sobre suas propriedades e

    métodos e alterar seus membros (mesmo privados)
  40. 84.

    frameworks web como Laravel e Symfony possuem um contêiner de

    injeção de dependências como parte integrante de suas estruturas
  41. 85.

    um contêiner deve ser capaz de gerenciar qualquer objeto e

    os objetos não devem saber que são gerenciados por contêineres
  42. 86.
  43. 87.

    um contêiner não gerencia todos os seus objetos, ele gerencia

    objetos de serviço como loggers, mailers…
  44. 88.

    a injeção de dependências torna mais fácil de personalizar, permite

    usar estratégias diferentes e facilita a utilização de mock sem a necessidade de alterar a classe
  45. 91.
  46. 92.

    o objetivo é padronizar como frameworks e bibliotecas fazem o

    uso de contêineres para obter objetos e parâmetros
  47. 95.
  48. 99.

    pacotes que fornecem uma implementação da PSR de contêineres devem

    declarar que fornecem a psr/container-implementation
  49. 100.
  50. 102.
  51. 104.

    recomenda-se injetar diretamente as dependências ao invés de obtê-las 


    * lembre-se do princípio da inversão de controle (IoC)
  52. 106.
  53. 108.
  54. 109.

    1. prefira classes com alta coesão e baixo acoplamento 2.

    utilize injeção de dependências ao seu favor 3. classes devem depender de abstrações ou interfaces 4. utilize um contêiner para o gerenciamento de suas dependências 5. o seu framework favorito provavelmente disponibiliza um contêiner para uso
  55. 112.
  56. 113.
  57. 114.

    bit.ly/workshop-php74 Informações:
 
 • o PHP 7.4 é a maior

    release em relação ao número de funcionalidades • analisaremos a evolução da linguagem • abordaremos as principais funcionalidades do PHP 7.4 como typed properties, arrow functions, spread operator em arrays, preloading, FFI (foreign function interface), operador de atribuição null coalesce, numeric literal separator entre outras de forma prática • e o que há por vir?