2. BONJOUR
MATTHIEU NAPOLI
My C-Sense ( myclabs ), Lyon
mnapoli.fr / @matthieunapoli
github.com/mnapoli
PHP-DI
Container d'injection de dépendances
depuis Mars 2012
4. INJECTION DE DÉPENDANCES
Construire son code pour ne plus créer ses dépendances
=> méthode
CONTAINER
Construit des objets et injecte les dépendances
=> outil
6. WORKFLOW D'UN CODE CLASSIQUE
Application :
$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();
}
7. 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, une
BDD, du cache, …
Extensibilité : mon système de log loggue dans un fichier, j'aimerai
qu'il écrive en BDD et les envoie par email…
Coupling : je veux changer de système de cache (ou sa config) -> je
dois changer le code partout…
9. TRANSFORMATION
Avant :
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();
}
}
10. WORKFLOW D'UN CODE UTILISANT L'INJECTION
DE 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();
}
11. INVERSION OF CONTROL
=> dépendances choisies lors de l'exécution
Possibilité de remplacer les dépendances injectées
Dans les classes, on ne gère plus les dépendances, leurs
configurations…
Code plus générique :
code against interfaces
12. CODE AGAINST INTERFACES
class StoreService {
public function __construct(GeolocationService $geolocationService) { … }
}
interface GeolocationService {
public function getCoordinates($address);
}
class GoogleMaps implements GeolocationService { … }
class OpenStreetMap implements GeolocationService { … }
13. MAIS
Nécessite de gérer les dépendances dans l'application
$bim = new Bim();
$bar = new Bar($bim);
$foo = new FooController($bar);
15. WORKFLOW D'UN CODE UTILISANT UN
CONTAINER
Application :
$foo = $container->get('FooController');
$foo->doSomething();
Classe FooController :
public function loginAction() {
$this->bar->doSomething();
}
Classe Bar :
public function doSomething() {
$this->bim->doSomethingElse();
}
20. 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
21. CALLBACKS
$container = new Container();
$container->set('Bim', function() {
return new Bim();
});
$container->set('Bar', function() use ($container) {
return new Bar($bim);
});
Verbeux, mais efficace
28. ANNOTATIONS
Inspiré de Java/Spring
use DIAnnotationInject;
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
31. FUTUR
PHP-DI : v4.0, intégration avec d'autres frameworks
PHP-FIG : collaboration pour une PSR ContainerInterface
Communauté : diffusion, meilleure doc et best-practices dans ZF2
et Symfony 2…