Qu'est-ce que la Dependency Injection en PHP et pourquoi en a-t-on besoin ?
\n\nImaginez que vous construisez une maison. Au lieu de fabriquer vous-même chaque brique, vous les commandez simplement et utilisez des briques prêtes à l'emploi. Dependency Injection (DI) en programmation fonctionne sur le même principe — vous ne créez pas d'objets à l'intérieur d'une classe, mais vous les recevez de l'extérieur. Cela rend votre code flexible, testable et compréhensible.
\n\nEn PHP, comme dans tout langage orienté objet, les classes dépendent souvent d'autres classes. Le problème survient lorsque les dépendances sont créées directement à l'intérieur de la classe — on appelle cela un couplage fort (tight coupling). La Dependency Injection résout ce problème en transmettant les dépendances de l'extérieur.
\n\nLe problème sans Dependency Injection
\nConsidérons un exemple typique où la classe UserService crée elle-même l'objet base de données :
<?php\nclass Database {\n public function query($sql) {\n // Logique de requête\n return "Résultat : " . $sql;\n }\n}\n\nclass UserService {\n private $db;\n \n public function __construct() {\n // Couplage fort — la classe crée elle-même la dépendance\n $this->db = new Database();\n }\n \n public function getUser($id) {\n return $this->db->query("SELECT * FROM users WHERE id = $id");\n }\n}\n\n$service = new UserService();\necho $service->getUser(1);\n?>\n\nProblèmes de cette approche :
\n- \n
- Impossible de remplacer
Databasepar une autre implémentation (par exemple, pour les tests) \n - Difficile à tester — impossible d'utiliser un mock (simulation) \n
- Le code devient monolithique et difficile à étendre \n
Solution : Injection de dépendance par le constructeur
\nRéécrivons maintenant la même classe en utilisant la Dependency Injection :
\n\n<?php\nclass UserService {\n private $db;\n \n // La dépendance est transmise de l'extérieur\n public function __construct(Database $db) {\n $this->db = $db;\n }\n \n public function getUser($id) {\n return $this->db->query("SELECT * FROM users WHERE id = $id");\n }\n}\n\n// On crée la dépendance séparément\n$database = new Database();\n$service = new UserService($database);\necho $service->getUser(1);\n?>\n\nMaintenant, UserService ne sait pas comment Database est créée. Il utilise simplement ce qu'on lui a transmis. C'est ce qu'on appelle l'injection de dépendance.
Types de Dependency Injection en PHP
\nIl existe trois principales façons d'injecter des dépendances. Examinons chacune avec des exemples.
\n\n1. Injection par le constructeur (Constructor Injection)
\nLa méthode la plus courante et recommandée. Les dépendances sont transmises lors de la création de l'objet via le constructeur.
\n\n<?php\nclass Logger {\n public function log($message) {\n echo "[LOG] : " . $message;\n }\n}\n\nclass OrderProcessor {\n private $logger;\n \n // Dépendance dans le constructeur\n public function __construct(Logger $logger) {\n $this->logger = $logger;\n }\n \n public function process($order) {\n // Traitement de la commande\n $this->logger->log("Commande traitée : " . $order);\n }\n}\n\n$logger = new Logger();\n$processor = new OrderProcessor($logger);\n$processor->process("Commande #123");\n?>\n\nAvantages : la dépendance est toujours disponible, l'objet est toujours dans un état valide. Inconvénients : si les dépendances sont nombreuses, le constructeur peut devenir lourd.
\n\n2. Injection par setter (Setter Injection)
\nUtilisée lorsque la dépendance peut être facultative ou doit être remplacée pendant le fonctionnement de l'objet.
\n\n<?php\nclass MailService {\n private $transport;\n \n // Setter pour la dépendance\n public function setTransport($transport) {\n $this->transport = $transport;\n }\n \n public function send($to, $mess