Injection de dépendances
Fait partie de la section Programmation Orientée Objet du Journey PHP de Coddy — leçon 57 sur 91.
Dans la leçon précédente, vous avez vu comment la composition permet à une Car de contenir un objet Engine. Mais il y a un problème avec la création de dépendances à l'intérieur de la classe - cela rend le code rigide et difficile à tester. L'injection de dépendances résout ce problème en passant les dépendances de l'extérieur plutôt qu'en les créant en interne.
Comparez ces deux approches :
<?php
// Sans DI - dépendance créée à l'intérieur
class Car {
private Engine $engine;
public function __construct() {
$this->engine = new Engine(); // Fortement couplé
}
}
// Avec DI - dépendance transmise
class Car {
public function __construct(private Engine $engine) {}
}
$engine = new Engine();
$car = new Car($engine); // Injecté de l'extérieur
La deuxième approche est l'injection de dépendances. La Car ne crée pas son propre moteur - elle en reçoit un. Ce simple changement présente des avantages puissants : vous pouvez passer différents types de moteurs, échanger les implémentations pour les tests, et la classe devient plus flexible.
Pour encore plus de flexibilité, injectez des interfaces au lieu de classes concrètes :
<?php
interface EngineInterface {
public function start(): string;
}
class Car {
public function __construct(private EngineInterface $engine) {}
public function start(): string {
return $this->engine->start();
}
}
Maintenant, Car fonctionne avec n'importe quelle classe implémentant EngineInterface - un moteur à essence, un moteur électrique ou un mock pour les tests. Ce découplage est la raison pour laquelle l'injection de dépendances est fondamentale pour écrire des applications PHP maintenables et testables.
Défi
FacileConstruisons un système de notification qui démontre la puissance de l'injection de dépendances. Au lieu de coder en dur la manière dont les messages sont envoyés, vous allez créer un système flexible où la méthode de distribution peut être remplacée facilement.
Vous organiserez votre code sur quatre fichiers :
MessageSenderInterface.php— Définissez une interface nomméeMessageSenderInterfaceavec une seule méthodesend(string $recipient, string $message): string. Cette interface établit le contrat que tout expéditeur de message doit suivre.EmailSender.php— Créez une classeEmailSenderqui implémenteMessageSenderInterface. Incluez le fichier de l'interface. La méthodesend()doit retourner"Email to $recipient: $message".NotificationService.php— Créez une classeNotificationServicequi reçoit sa dépendance via le constructeur. Incluez le fichier de l'interface. La classe doit :- Accepter un
MessageSenderInterfacedans son constructeur en utilisant la promotion de propriété de constructeur - Avoir une méthode
notify(string $recipient, string $message)qui délègue à l'expéditeur injecté et retourne son résultat
NotificationServicedépend de l'interface, et non d'une classe concrète. Cela signifie que vous pourriez injecter n'importe quel expéditeur implémentant l'interface sans modifier le service.- Accepter un
main.php— Incluez les fichiers EmailSender et NotificationService. Vous recevrez deux entrées : un destinataire et un message. Créez unEmailSender, injectez-le dans unNotificationService, puis appeleznotify()et affichez le résultat.
Ce modèle maintient votre NotificationService flexible — il fonctionne avec n'importe quel expéditeur que vous injectez, qu'il s'agisse d'un e-mail, d'un SMS ou de quelque chose que vous n'avez pas encore construit. Le service ne crée pas ses propres dépendances ; il les reçoit de l'extérieur.
Aide-mémoire
L'injection de dépendances (DI) est une technique où les dépendances sont transmises à une classe de l'extérieur plutôt que d'être créées en interne.
Sans DI (fortement couplé) :
<?php
class Car {
private Engine $engine;
public function __construct() {
$this->engine = new Engine(); // Créé à l'intérieur
}
}Avec DI (faiblement couplé) :
<?php
class Car {
public function __construct(private Engine $engine) {}
}
$engine = new Engine();
$car = new Car($engine); // Injecté de l'extérieurPour une flexibilité maximale, injectez des interfaces au lieu de classes concrètes :
<?php
interface EngineInterface {
public function start(): string;
}
class Car {
public function __construct(private EngineInterface $engine) {}
public function start(): string {
return $this->engine->start();
}
}Cela permet à Car de fonctionner avec n'importe quelle classe implémentant EngineInterface, rendant le code plus facile à maintenir et à tester.
Essayez vous-même
<?php
require_once 'EmailSender.php';
require_once 'NotificationService.php';
// Lire l'entrée
$recipient = trim(fgets(STDIN));
$message = trim(fgets(STDIN));
// TODO : Créer une instance de EmailSender
// TODO : L'injecter dans un NotificationService
// TODO : Appeler notify() et afficher le résultat
?>Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation Orientée Objet
1Les bases de la POO
Fichiers externesIntroduction à la POOClasses vs ObjetsLe mot-clé $thisMéthodesPropriétésConstructeur (__construct)Destructeur (__destruct)Récapitulatif - Calculatrice simple4Héritage
Héritage de baseLe mot-clé parent::Redéfinition de méthodeLe mot-clé finalClasses abstraitesRécapitulatif - Hiérarchie des employés7Encapsulation
Public, Protégé, PrivéModificateurs d'accès en détailGetters et SettersMasquage d'informationPromotion de constructeur (8.0)Récapitulatif - Système de gestion d'étudiants10Concepts avancés de la POO
Composition vs HéritageInjection de dépendancesClasses anonymesÉnumérations (PHP 8.1)Fibers (PHP 8.1)Clonage d'objets : analyse approfondieGénérateurs et Itérateurs13Patrons de conception Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Méthode ModèlePatron ÉtatPatron CompositePatron Repository2Espaces de noms et Autoloading
Introduction aux espaces de nomsLe mot-clé useStandard d'Autoloading PSR-4L'Autoloader ComposerRécapitulatif - Projet organisé5Interfaces et Contrats
Introduction aux InterfacesImplémentation d'InterfacesImplémentation d'Interfaces MultiplesInterface vs Classe AbstraiteType Hinting avec les InterfacesRécapitulatif - Calculateur de Formes8Méthodes magiques
Introduction aux méthodes magiques__toString & __debugInfo__get, __set, __isset, __unset__call & __callStatic__clone & Clonage d'objets__serialize & __unserializeRécapitulatif - Collection personnalisée3Propriétés de classe
Propriétés d'instance vs Propriétés statiquesConstantes dans les classesMéthodes et propriétés statiquesPropriétés privées et protégéesPropriétés readonly (PHP 8.1)Récapitulatif - Gestionnaire de compte bancaire6Polymorphisme
Retour sur la redéfinition de méthodePolymorphisme via les interfacesType Hinting et Types d'unionLiaison statique tardiveRécapitulatif - Processeur de paiement9Traits
Introduction aux TraitsUtilisation de plusieurs TraitsRésolution des conflits de TraitsMéthodes abstraites dans les TraitsTraits vs Héritage12Patrons de conception Partie 1
Introduction aux patrons de conceptionPatron SingletonPatron FabriquePatron ObservateurPatron Stratégie