Qu’est-ce que l’injection de dépendances en PHP et comment l’utiliser

Une méthodologie populaire et bien connue de développement logiciel est appelée injection de dépendances, ce qui permet de faciliter le flux en garantissant que votre logiciel a toujours accès aux outils dont il a besoin. Beaucoup essaient de rendre cette méthodologie assez complexe, mais ce n'est vraiment pas le cas.

Voyons ce qu'est l'injection de dépendances, comment elle fonctionne et comment elle profitera à votre logiciel.

Qu'est-ce que l'injection de dépendance?

Une bonne analogie pour l'injection de dépendances est un travailleur doté d'une boîte à outils qui accompagne le logiciel au fur et à mesure de son traitement, garantissant ainsi que tout se déroule correctement. La boîte à outils peut contenir toutes sortes de choses, y compris des variables, des tableaux, des objets , des fermetures et tout ce qui est nécessaire pour accomplir la tâche à accomplir.

Lorsque le travailleur commence une nouvelle tâche (par exemple, une classe ou une méthode), il examinera les exigences nécessaires et, sans réfléchir, sortira les différents outils nécessaires pour terminer le travail. C'est l'injection de dépendance en un mot.

Vous pouvez remplir votre boîte à outils avec tout ce dont vous avez besoin, puis dans les classes et méthodes du logiciel, spécifiez les outils dont vous avez besoin, et ils seront automatiquement là pour vous.

Installer Apex Container

Il existe de nombreuses implémentations différentes, mais toutes fonctionnent essentiellement de la même manière, et nous utiliserons le conteneur Apex car il est simple et direct. Il est supposé que PHP est déjà installé et vous pouvez vérifier si Composer est installé ou non avec la commande:

 composer --version

Si vous recevez une erreur «commande introuvable», vous pouvez installer Composer avec la commande suivante:

 sudo curl -sS https://getcomposer.org/installer | sudo php -- --install-dir=/usr/local/bin --filename=composer

Créez maintenant un répertoire vide et, dans le répertoire, exécutez les commandes suivantes:

 composer require apex/container
composer require twig/twig

Cela téléchargera à la fois le conteneur Apex et le moteur de modèle Twig populaire qui sera utilisé dans les exemples ci-dessous. Les deux peuvent être trouvés dans le sous-répertoire / vendor /.

Injectez vos outils

Créons une classe rapide appelée Car avec le code suivant:

 
<?php
use TwigLoaderArrayLoader;
class Car
{
public function __construct(
public string $model,
public string $color,
public ArrayLoader $db
) {
echo "I'm a $color $model and have a " . $db::class . "
";
}
}

Il s'agit d'une classe simple avec deux propriétés, la marque et la couleur d'une voiture, et charge la classe 'ArrayLoader' de Twig. Enregistrez-le sous car.php et préparez-vous à utiliser la magie de l'injection de dépendances. Ouvrez un autre fichier vierge et ajoutez le code suivant:

 
<?php
use ApexContainerContainer;
// Load Composer packages, and the car.php file
require_once(__DIR__ . '/vendor/autoload.php');
require_once(__DIR__ . '/car.php');
// Create container, and add a couple tools
$cntr = new Container(use_attributes: true);
$cntr->set('model', 'Jaguar');
$cntr->set('color', 'silver');
// Create our car object
$car = $cntr->make('Car');
$car2 = $cntr->make('car', ['color' => 'red']);

Enregistrez et exécutez ce code dans le terminal, et les résultats seront:

 I'm a silver Jaguar and have a TwigLoaderArrayLoader
I'm a red Jaguar and have a TwigLoaderArrayLoader

Dans le code ci-dessus, vous avez instancié le conteneur (c'est-à-dire la boîte à outils), et ajouté quelques outils, la couleur et la marque d'une voiture. Au lieu de créer l'objet voiture avec la nouvelle voiture normale (); , il a été créé via la méthode make () du conteneur. Cela passait d'abord par la classe pour vérifier les exigences, puis regardait quels éléments (c.-à-d. Outils) nous avions disponibles, et les injectait dans la classe avant de la rendre.

Vous remarquerez la déclaration d' utilisation en haut du fichier au ArrayLoader, et le troisième argument du constructeur demande également un ArrayLoader . Lorsque le conteneur a examiné les exigences de la classe, il a remarqué ces deux aspects, a créé automatiquement une instance d' ArrayLoader `et l'a injectée dans le constructeur. C'est ce qu'on appelle le câblage automatique.

Extension avec injection d'attribut

Pour aller plus loin, au lieu de n'injecter que dans le constructeur, nous pouvons également injecter directement dans les propriétés via des attributs. Modifiez le fichier de voiture et changez-le en:

 
<?php
use TwigLoaderArrayLoader;
use ApexContainerContainer;
class Car
{
#[Inject(Container::class)]
public Container $cntr;
public function __construct(
public string $model,
public string $color,
public ArrayLoader $db
) {
echo "I'm a $color $model and have a " . $db::class . "
";
}
function getCost()
{
echo "Class is " . $this->cntr::class . "
";
}
}

Les seules modifications ont été une nouvelle déclaration d'utilisation a été ajoutée, la propriété avec l' attribut à la classe conteneur a été ajouté, et nous avons ajouté une nouvelle getCost () fonction . Au bas du code de test que vous avez précédemment exécuté, ajoutez la ligne:

 $car->getCost();

Maintenant, exécutez à nouveau le code et les résultats seront:

 I'm a silver Jaguar and have a TwigLoaderArrayLoader
I'm a red Jaguar and have a TwigLoaderArrayLoader
Class is ApexContainerContainer

Cette fois, lorsque la classe car.php a été chargée, le conteneur a également examiné ses propriétés, a remarqué l'attribut Inject qui appelait la classe de conteneur et a injecté une instance de celle-ci. L'injection via des attributs de cette manière est parfois préférée car elle permet de garder les choses plus propres et plus lisibles.

Obtenez vos propres outils

Au lieu de toujours injecter des éléments, que se passe-t-il si vous souhaitez récupérer vous-même un élément du conteneur? Cela peut facilement être fait avec la méthode get () du conteneur. Dans le fichier car.php , modifiez la fonction getCost () précédemment ajoutée avec:

 
function getCost()
{
$price = $this->cntr->get('car_price');
echo "The price is $price
";
}

Maintenant, dans le code de test que vous avez exécuté, n'importe où avant la ligne qui appelle getCost (), ajoutez une ligne telle que:

 $cntr->set('car_price', 24995);

Maintenant, exécutez le code et les résultats seront:

 I'm a silver Jaguar and have a TwigLoaderArrayLoader
I'm a red Jaguar and have a TwigLoaderArrayLoader
Price is 24999

Vous n'avez pas nécessairement besoin d'injecter vos éléments et pouvez toujours facilement récupérer ce dont vous avez besoin avec la méthode get () comme indiqué ci-dessus.

Aller de l'avant avec l'injection de dépendances

Vous avez maintenant une bonne vue d'ensemble de ce qu'est exactement l'injection de dépendances et de son fonctionnement. Encore une fois, ce qui précède n'est qu'une des nombreuses implémentations, mais toutes les implémentations fonctionnent de la même manière avec les méthodes get () / set () / make () .

Il y a encore plus à l'injection de dépendances, comme le fichier de définitions et l'injection de méthode. Si vous êtes intéressé, veuillez consulter le manuel Apex Container ou d'autres implémentations.