La POO en PHPInjection de dépendances

Télécharger la vidéo

L'injection de dépendance (DI pour les intimes) est un design pattern qui permet de solutionner la problématique de communication entre les classes. Pour comprendre l'interêt de ce design pattern il est important de comprendre la problématique, aussi prenons l'exemple d'une classe se connectant à la base de donnée :

class Article{

    private $database; 

    public function __construct(){
        $this->database = new MySQLDatabase('blog');
    }

}

Mais que se passe-t-il si je souhaite me connecter à une autre base de donnée ? Je me retrouve fatalement bloqué car je dois aloer modifier toutes mes classes. La première idée serait alors de passer en paramètre au constructeur le nom de la base à utiliser.

public function __construct($database){
    $this->database = new MySQLDatabase($database);
}

Même si cette solution offre plus de flexibilité, on se retrouve quand même avec un problème de logique (pourquoi la classe article devrait avoir à se soucier du nom de la base de donnée ?) et d'évolution (et si je veux utiliser une autre classe que MySQLDatabase ?).

La solution à tous nos problème est de passer directement au constructeur l'objet que l'on souhaite utiliser.

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

// Et quand on construit l'objet
$db = new MySQLDatabase('blog');
$article = new Article($db); 

Les 2 classes sont donc bien indépendante et c'est au niveau de notre application que l'on va "injecter" nos objets les uns dans les autres. Cette approche permet de rendre notre code beaucoup plus flexible. Vous vous dites peut être que mon code est du coup beaucoup plus complexe à écrire. Pour nous simplifier la tache on peut alors reprendre le principe des factory pour se créer une sorte de conteneur qui va se charger de gérer la dépendance à notre place.

class DIContainer{

    private static $db_instance; 

    /**
    *  Permet de retourner un nouvel article
    *  @return Article
    **/
    public function getArticle(){
        return new Article($this->getDatabase()); 
    }

    /**
    * Permet de retourner une instance unique de la connexion à la base de donnée
    * @return MySQLDatabase
    **/
    public function getDatabase(){
        if(self::$db_instance){
            return new MySQLDatabase('blog'); 
        } else {
            return self::$db_instance;
        }
    }

}

Cette simple classe nous permet de contrebalancer la lourdeur d'écriture et rend du coup la classe Article aussi simple à utiliser qu'avant.

$container = new DIContainer(); // On pourra créer un singleton par la suite si besoin
$article = $container->getArticle();