[FR] Injection de dépendances, Containers & PHP-DI

32
INJECTION DE DÉPENDANCES, CONTAINERS & PHP-DI

description

[French] Présentation du principe d'injection de dépendances, des containers et de PHP-DI.

Transcript of [FR] Injection de dépendances, Containers & PHP-DI

Page 1: [FR] Injection de dépendances, Containers & PHP-DI

INJECTION DEDÉPENDANCES,

CONTAINERS & PHP-DI

Page 2: [FR] Injection de dépendances, Containers & PHP-DI

BONJOURMATTHIEU NAPOLI

My C-Sense ( ), Lyonmyclabs

/ mnapoli.fr @matthieunapoli

github.com/mnapoli

PHP-DIContainer d'injection de dépendances

depuis Mars 2012

Page 3: [FR] Injection de dépendances, Containers & PHP-DI

DI ≠ DIC

Page 4: [FR] Injection de dépendances, Containers & PHP-DI

INJECTION DE DÉPENDANCESConstruire son code pour ne plus créer ses dépendances

=> méthode

CONTAINERConstruit des objets et injecte les dépendances

=> outil

Page 5: [FR] Injection de dépendances, Containers & PHP-DI

INJECTION DEDÉPENDANCES

Page 6: [FR] Injection de dépendances, Containers & PHP-DI

WORKFLOW D'UN CODE CLASSIQUEApplication :

$foo = new FooController();$foo->loginAction();

Classe FooController :public function loginAction() { $bar = new Bar(); // ou $bar = Bar::getInstance() $bar->doSomething();}

Classe Bar :public function doSomething() { $bim = new Bim(); // ou $bim = Bim::getInstance() $bim->doSomethingElse();}

Page 7: [FR] Injection de dépendances, Containers & PHP-DI

WORKFLOW D'UN CODE CLASSIQUE=> dépendances choisies lors de l'écriture du code (hard-coded)

Tests : tester du code qui utilise un service web, des fichiers, uneBDD, du cache, …Extensibilité : mon système de log loggue dans un fichier, j'aimeraiqu'il écrive en BDD et les envoie par email…Coupling : je veux changer de système de cache (ou sa config) -> jedois changer le code partout…

Page 8: [FR] Injection de dépendances, Containers & PHP-DI

TRANSFORMATION

Page 9: [FR] Injection de dépendances, Containers & PHP-DI

TRANSFORMATIONAvant :

class FooController { public function loginAction() { $bar = new Bar(); // ou $bar = Bar::getInstance() $bar->doSomething(); }}

Après :class FooController { private $bar;

public function __construct(Bar $bar) { $this->bar = $bar; }

public function loginAction() { $this->bar->doSomething(); }}

Page 10: [FR] Injection de dépendances, Containers & PHP-DI

WORKFLOW D'UN CODE UTILISANT L'INJECTIONDE DÉPENDANCES

Application :$bim = new Bim();$bar = new Bar($bim);$foo = new FooController($bar);

$foo->loginAction();

Classe FooController :public function loginAction() { $this->bar->doSomething();}

Classe Bar :public function doSomething() { $this->bim->doSomethingElse();}

Page 11: [FR] Injection de dépendances, Containers & PHP-DI

INVERSION OF CONTROL=> dépendances choisies lors de l'exécution

Possibilité de remplacer les dépendances injectéesDans les classes, on ne gère plus les dépendances, leursconfigurations…Code plus générique :

code against interfaces

Page 12: [FR] Injection de dépendances, Containers & PHP-DI

CODE AGAINST INTERFACESclass StoreService {

public function __construct(GeolocationService $geolocationService) { … }

}

interface GeolocationService {

public function getCoordinates($address);

}

class GoogleMaps implements GeolocationService { … }

class OpenStreetMap implements GeolocationService { … }

Page 13: [FR] Injection de dépendances, Containers & PHP-DI

MAISNécessite de gérer les dépendances dans l'application

$bim = new Bim();$bar = new Bar($bim);$foo = new FooController($bar);

Page 14: [FR] Injection de dépendances, Containers & PHP-DI

CONTAINER

Page 15: [FR] Injection de dépendances, Containers & PHP-DI

WORKFLOW D'UN CODE UTILISANT UNCONTAINER

Application :$foo = $container->get('FooController');

$foo->doSomething();

Classe FooController :public function loginAction() { $this->bar->doSomething();}

Classe Bar :public function doSomething() { $this->bim->doSomethingElse();}

Page 16: [FR] Injection de dépendances, Containers & PHP-DI

$foo = $container->get('FooController');

=$bim = new Bim();$bar = new Bar($bim);$foo = new FooController($bar);

Page 17: [FR] Injection de dépendances, Containers & PHP-DI

Le container fait les injections, et aide à construire les graphes d'objets

Page 18: [FR] Injection de dépendances, Containers & PHP-DI

ATTENTION !$foo = $container->get('FooController');

Service Locator : anti-pattern

Page 19: [FR] Injection de dépendances, Containers & PHP-DI

CONFIGURATION DU CONTAINERNécessite de configurer le container pour qu'il injecte les bons objets

Chaque container se configure différement

Page 20: [FR] Injection de dépendances, Containers & PHP-DI

EXEMPLE SIMPLE$container = new Container();

$bim = new Bim();$bar = new Bar($bim);

$container->set('Bim', $bim);$container->set('Bar', $bar);

Problème : initialise tous les objets à chaque requête

Page 21: [FR] Injection de dépendances, Containers & PHP-DI

CALLBACKS$container = new Container();

$container->set('Bim', function() { return new Bim();});$container->set('Bar', function() use ($container) { return new Bar($bim);});

Verbeux, mais efficace

Page 22: [FR] Injection de dépendances, Containers & PHP-DI

FICHIERS DE CONFIGURATIONTableau PHP

YAML

XML

Formats différents pour chaque librairie

Page 23: [FR] Injection de dépendances, Containers & PHP-DI

Symfony DI

Zend\Di (+ tous les autres)

Pimple

Aura DI

Laravel

Mouf

Orno

PPI

Page 24: [FR] Injection de dépendances, Containers & PHP-DI

PHP-DI

Page 25: [FR] Injection de dépendances, Containers & PHP-DI

POURQUOI ?PratiqueVolontairement copieurFramework-agnostic

Page 26: [FR] Injection de dépendances, Containers & PHP-DI

PHP-DIv1.0 (août 2012) : injections via annotations (PC)

v2.0 (décembre 2012) : refactoring, version stable

v3.0 (avril 2013) : annotations, config PHP, YAML, …

v3.5 (octobre 2013)

Page 27: [FR] Injection de dépendances, Containers & PHP-DI

REFLECTIONRésolution de dépendances intelligente

class Foo { public function __construct(Bar $param1) { }}

~ 90% des cas -> 0 configuration

Page 28: [FR] Injection de dépendances, Containers & PHP-DI

ANNOTATIONSInspiré de Java/Spring

use DI\Annotation\Inject;

class UserController { /** * @Inject */ private $userRepository;

public function loginAction($email, $password) { $user = $this->userRepository->login($email, $password); // ... }}

Pas la solution à tout, mais très pratique dans les contrôleurs

Page 29: [FR] Injection de dépendances, Containers & PHP-DI

CONFIGURATION PHP$container->set('Bar');

$container->set('Foo') ->withConstructor(array('Bar'));

$container->set('My\Interface') ->bindTo('My\Implementation');

Page 30: [FR] Injection de dépendances, Containers & PHP-DI

YAMLBar:

Foo: constructor: [ Bar ]

My\Interface: class: My\Implementation

Page 31: [FR] Injection de dépendances, Containers & PHP-DI

FUTURPHP-DI : v4.0, intégration avec d'autres frameworks

: collaboration pour une PSR ContainerInterfaceCommunauté : diffusion, meilleure doc et best-practices dans ZF2

et Symfony 2…

PHP-FIG

Page 32: [FR] Injection de dépendances, Containers & PHP-DI

MERCI

Site officiel :

GitHub :

Twitter :

php-di.org

mnapoli/PHP-DI

@PHPDI