Slide 1

Slide 1 text

Marcel Gonçalves dos Santos @marcelgsantos desmistificando injeção de dependências

Slide 2

Slide 2 text

pensandonaweb.com.br desenvolvedor web full-stack Marcel Gonçalves dos Santos @marcelgsantos

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

@femugsp sp.femug.com

Slide 5

Slide 5 text

@phpsp phpsp.org.br

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

O que é uma dependência?

Slide 8

Slide 8 text

uma dependência é um outro objeto que a sua classe necessita para ela funcionar

Slide 9

Slide 9 text

!// 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 } }

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

a referência é feita ao chamar uma função, usar algum dado ou usar algum tipo definido no módulo A

Slide 12

Slide 12 text

O que é um objeto?

Slide 13

Slide 13 text

um objeto é uma representação concreta de uma abstração…

Slide 14

Slide 14 text

…que possui características, comportamentos e estado atual

Slide 15

Slide 15 text

!// 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}!"; } }

Slide 16

Slide 16 text

!// 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!

Slide 17

Slide 17 text

!// current state of $alice object
 var_dump($alice); !/* class User#3 (2) { private $name !=> string(5) "Alice" private $age !=> int(22) } !*/

Slide 18

Slide 18 text

Coesão e acoplamento

Slide 19

Slide 19 text

indica o grau de relação entre os membros de um módulo coesão

Slide 20

Slide 20 text

!// 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 } }

Slide 21

Slide 21 text

indica o grau de dependência entre classes acoplamento

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

!// 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 } }

Slide 24

Slide 24 text

o acoplamento é algo desejado, porém, que deve ser controlado

Slide 25

Slide 25 text

ao controlar o acoplamento, o software torna-se mais flexível e fácil de manter

Slide 26

Slide 26 text

Como reduzir o acoplamento?

Slide 27

Slide 27 text

pode-se reduzir o acoplamento através da injeção de dependências

Slide 28

Slide 28 text

O que é injeção de dependências?

Slide 29

Slide 29 text

a injeção de dependências é fornecer uma dependência do mundo externo para uma classe

Slide 30

Slide 30 text

a injeção de dependências pode ser feita através de um parâmetro do construtor ou utilizando um método setter

Slide 31

Slide 31 text

!// dependency injection via constructor
 class Car { private $engine; public function !__construct(Engine $engine) { $this!->engine = $engine; } public function start() { $this!->engine!->start(); } }

Slide 32

Slide 32 text

!// injecting the dependency
 $engine = new Engine(); $car = new Car($engine); $car!->start(); !// Starting the engine

Slide 33

Slide 33 text

não é recomendável instanciar uma dependência no método construtor da sua classe utilizando new

Slide 34

Slide 34 text

!// 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(); } }

Slide 35

Slide 35 text

isso torna a sua classe altamente acoplada a sua dependência

Slide 36

Slide 36 text

lembre-se que o objetivo é diminuir o acoplamento entre a classe e suas dependências

Slide 37

Slide 37 text

“prefira classes com alta coesão e baixo acoplamento”

Slide 38

Slide 38 text

Princípio da inversão de dependência
 Dependency Inversion Principle

Slide 39

Slide 39 text

o princípio de inversão de dependência é a letra “D” do SOLID

Slide 40

Slide 40 text

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:

Slide 41

Slide 41 text

Classe A Classe B referencia

Slide 42

Slide 42 text

!// 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 } }

Slide 43

Slide 43 text

!// 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()); } }

Slide 44

Slide 44 text

uma classe não deve depender de um módulo de baixo nível

Slide 45

Slide 45 text

Classe B referencia Classe A Interface implementa

Slide 46

Slide 46 text

!// geolocation services abstraction (contract) !// each concrete implementation must follow this contract interface GeolocationService { public function getCoordinatesFromAddress($address); }

Slide 47

Slide 47 text

!// 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 } }

Slide 48

Slide 48 text

!// 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()); } }

Slide 49

Slide 49 text

uma classe deve depender de um contrato, abstração ou interface

Slide 50

Slide 50 text

ao depender de abstrações você desacopla o seu código da dependência

Slide 51

Slide 51 text

Inversão de Controle
 Inversion of Control

Slide 52

Slide 52 text

a inversão de controle é sobre deixar de ir atrás das dependências e deixar que elas sejam levadas até você

Slide 53

Slide 53 text

Mais sobre injeção de dependências

Slide 54

Slide 54 text

a inversão de dependência é diferente da injeção de dependência

Slide 55

Slide 55 text

a injeção de dependência permite alcançar a inversão de dependência

Slide 56

Slide 56 text

é possível utilizar a injeção de dependência sem a necessidade de bibliotecas

Slide 57

Slide 57 text

!// dependency injection is possible without libraries
 $geolocationService = new GoogleMaps(); $storeService = new StoreService($geolocationService);

Slide 58

Slide 58 text

ao utilizar injeção de dependência o código é desacoplado de implementações de baixo nível

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

ter muitas dependências pode ser considerado um mau cheiro ou bad smell

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

!// complex instantiation process
 $handler = new StreamHandler(!__DIR!__ . '/email.log'); $logger = new Logger('main', [$handler]); $mailer = new Mailer($logger); $notifier = new UserNotifier($mailer);

Slide 63

Slide 63 text

Como tornar mais fácil o processo de instanciação?

Slide 64

Slide 64 text

o processo de instanciação de objetos se torna mais fácil ao utilizar um contêiner de injeção de dependência

Slide 65

Slide 65 text

O que é um contêiner de injeção de dependências?

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

um contêiner de injeção de dependências descreve objetos e suas dependências e instancia e configura os objetos sob demanda

Slide 68

Slide 68 text

!// get a StoreService object from container
 $storeService = $container!->get('StoreService');

Slide 69

Slide 69 text

!// config to inject a GoogleMaps instance when using 
 !// GeolocationService type hint
 $container!->set('GeolocationService', \DI\create(‘GoogleMaps'));

Slide 70

Slide 70 text

!// get a StoreService object from container (Laravel) $storeService = $this!->app!->make('StoreService');

Slide 71

Slide 71 text

!// config to inject a GoogleMaps instance when using 
 !// GeolocationService type hint (Laravel)
 $this!->app!->bind( 'App\Services\GeolocationService', 'App\Services\GoogleMaps' );

Slide 72

Slide 72 text

um contêiner de injeção de dependências é conhecido também como service container, IOC container ou dependency injection container (DIC)

Slide 73

Slide 73 text

class Mailer { public function mail($recipient, $content) { !// send an email to the recipient } }

Slide 74

Slide 74 text

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!'); } }

Slide 75

Slide 75 text

!// injecting the dependency manually
 
 $mailer = new Mailer(); $userManager = new UserManager($mailer);

Slide 76

Slide 76 text

!// get a UserManager object from container, the !// dependencies are resolved automatically
 $userManager = $container!->get('UserManager');

Slide 77

Slide 77 text

!// get a UserManager object from container, the !// dependencies are resolved automatically (Laravel) 
 $userManager = $this!->app!->make('UserManager');

Slide 78

Slide 78 text

o contêiner utiliza uma técnica chamada autowiring para analisar as dependências e criá-las conforme necessário

Slide 79

Slide 79 text

o autowiring permite a resolução automática das dependências

Slide 80

Slide 80 text

quando a resolução automática não é possível, utiliza-se arquivos de configuração

Slide 81

Slide 81 text

o autowiring é possível graças às anotações de tipo e o suporte à reflection

Slide 82

Slide 82 text

reflection é a capacidade de um programa inspecionar ele mesmo e modificar a sua lógica em tempo de execução

Slide 83

Slide 83 text

reflection é perguntar a um objeto sobre suas propriedades e métodos e alterar seus membros (mesmo privados)

Slide 84

Slide 84 text

frameworks web como Laravel e Symfony possuem um contêiner de injeção de dependências como parte integrante de suas estruturas

Slide 85

Slide 85 text

um contêiner deve ser capaz de gerenciar qualquer objeto e os objetos não devem saber que são gerenciados por contêineres

Slide 86

Slide 86 text

um contêiner pode também conter parâmetros que são utilizados para a configuração de objetos no contêiner

Slide 87

Slide 87 text

um contêiner não gerencia todos os seus objetos, ele gerencia objetos de serviço como loggers, mailers…

Slide 88

Slide 88 text

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

Slide 89

Slide 89 text

PSR-11
 Container Interface

Slide 90

Slide 90 text

a PSR-11 descreve uma interface comum para contêineres de injeção de dependência

Slide 91

Slide 91 text

No content

Slide 92

Slide 92 text

o objetivo é padronizar como frameworks e bibliotecas fazem o uso de contêineres para obter objetos e parâmetros

Slide 93

Slide 93 text

utiliza-se um identificador (string) para identificar unicamente um item contido no contêiner

Slide 94

Slide 94 text

um contêiner que segue a PSR-11 deve implementar a interface Psr\Container\ContainerInterface

Slide 95

Slide 95 text

No content

Slide 96

Slide 96 text

a interface ContainerInterface expõe os métodos get e has

Slide 97

Slide 97 text

o método get é responsável por obter uma instância de objeto do contêiner

Slide 98

Slide 98 text

o contêiner pode lançar a exceção NotFoundExceptionInterface caso o identificador informado não seja encontrado

Slide 99

Slide 99 text

pacotes que fornecem uma implementação da PSR de contêineres devem declarar que fornecem a psr/container-implementation

Slide 100

Slide 100 text

No content

Slide 101

Slide 101 text

existem inúmeras bibliotecas de injeção de dependências em PHP e cada uma possui suas características

Slide 102

Slide 102 text

No content

Slide 103

Slide 103 text

não se deve utilizar o contêiner de injeção de dependências como um service locator

Slide 104

Slide 104 text

recomenda-se injetar diretamente as dependências ao invés de obtê-las 
 * lembre-se do princípio da inversão de controle (IoC)

Slide 105

Slide 105 text

a PSR-11 ou Container Interface foi precedida pelo projeto container-interop

Slide 106

Slide 106 text

No content

Slide 107

Slide 107 text

o projeto container-interop serviu como base e preparou o caminho para a PSR-11

Slide 108

Slide 108 text

Conclusão

Slide 109

Slide 109 text

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

Slide 110

Slide 110 text

Referências

Slide 111

Slide 111 text

bit.ly/referencias-palestra-di

Slide 112

Slide 112 text

Avalie!

Slide 113

Slide 113 text

Anúncio!

Slide 114

Slide 114 text

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?

Slide 115

Slide 115 text

@marcelgsantos speakerdeck.com/marcelgsantos Obrigado. Perguntas?