Maison > développement back-end > tutoriel php > Comment construire votre propre conteneur d'injection de dépendance

Comment construire votre propre conteneur d'injection de dépendance

Jennifer Aniston
Libérer: 2025-02-15 13:22:12
original
611 Les gens l'ont consulté

Cet article examine comment construire un package PHP de conteneur d'injection de dépendance simple (conteneur DI). Tout le code de l'article, y compris les annotations PHPDOC et les tests unitaires (couverture de code à 100%), a été téléchargé sur le référentiel GitHub et répertorié sur Packagist.

How to Build Your Own Dependency Injection Container

Points clés:

  • La construction de conteneurs DI aide les développeurs à comprendre les principes de base de l'injection de dépendance et le mécanisme de travail des conteneurs.
  • Les conteneurs DI ont deux fonctions principales: "injection de dépendance" et "conteneur". Il doit être en mesure d'instancier et d'inclure des services en utilisant des méthodes d'injection de constructeur ou d'injection de setter.
  • Le conteneur d'injection de dépendance à symfony peut être utilisé comme référence pour créer des conteneurs personnalisés. Il divise la configuration du conteneur en paramètres et services, permettant un stockage sécurisé des clés d'application.
  • La création d'un conteneur DI implique la création d'un répertoire de projet, la création d'un fichier composer.json et la mise en œuvre d'une interface d'interopérabilité de conteneur. Cela implique également de créer des exceptions et des classes de référence.
  • La classe de conteneurs doit contenir des méthodes pour récupérer les services, vérifier si les services ont été définis, analyser les paramètres et initialiser les services. Il devrait également avoir un mécanisme de protection pour empêcher les références circulaires.

Planifiez notre conteneur d'injection de dépendance

Tout d'abord, nous avons divisé le "conteneur d'injection de dépendance" en deux rôles: "injection de dépendance" et "conteneur".

Les deux méthodes les plus couramment utilisées d'injection de dépendance sont l'injection du constructeur et l'injection de setter, c'est-à-dire passer des dépendances de classe à travers des paramètres du constructeur ou des appels de méthode. Si notre conteneur peut instancier et inclure des services, il doit être en mesure d'effectuer les deux opérations.

Pour être un conteneur, il doit être en mesure de stocker et de récupérer les instances du service. Il s'agit d'une tâche assez simple par rapport à la création d'un service, mais cela vaut toujours la peine d'être considéré. Le package container-interop fournit une interface qu'un ensemble de conteneurs peut implémenter. L'interface principale est ContainerInterface, qui définit deux méthodes: l'une pour la récupération des services et l'autre pour tester si le service est défini.

interface ContainerInterface
{
    public function get($id);
    public function has($id);
}
Copier après la connexion
Copier après la connexion

Apprenez d'autres conteneurs d'injection de dépendance

Le conteneur d'injection de dépendance à Symfony nous permet de définir les services de différentes manières. Dans YAML, la configuration du conteneur peut ressembler à ceci:

parameters:
    # ...
    mailer.transport: sendmail

services:
    mailer:
        class:     Mailer
        arguments: ["%mailer.transport%"]
    newsletter_manager:
        class:     NewsletterManager
        calls:
            - [setMailer, ["@mailer"]]
Copier après la connexion
Copier après la connexion

Symfony est très utile pour diviser la configuration du conteneur en paramètres et services. Cela permet aux touches d'application telles que les clés API, les clés de chiffrement et les jetons d'authentification d'être stockés dans des fichiers de paramètres exclus du référentiel de code source.

Dans PHP, la même configuration du composant d'injection de dépendance à symfony est la suivante:

use Symfony\Component\DependencyInjection\Reference;

// ...
$container->setParameter('mailer.transport', 'sendmail');

$container
    ->register('mailer', 'Mailer')
    ->addArgument('%mailer.transport%');

$container
    ->register('newsletter_manager', 'NewsletterManager')
    ->addMethodCall('setMailer', array(new Reference('mailer')));
Copier après la connexion

En utilisant l'objet setMailer dans un appel de méthode à Reference, la logique d'injection de dépendance peut détecter que cette valeur ne doit pas être transmise directement, mais doit être remplacée par le service qu'il fait référence dans le conteneur. Cela permet une injection de valeurs PHP et d'autres services faciles dans le service sans confusion.

Démarrer

Tout d'abord, créez un nouveau répertoire de projet et créez un fichier composer.json que le compositeur peut utiliser pour charger automatiquement notre classe. Actuellement, ce fichier ne fait que mapper l'espace de noms SitePointContainer dans le répertoire src.

interface ContainerInterface
{
    public function get($id);
    public function has($id);
}
Copier après la connexion
Copier après la connexion

Ensuite, car nous ferons en sorte que nos conteneurs implémentent des interfaces d'interopérabilité des conteneurs, nous devons les télécharger de compositeur et les ajouter à notre fichier composer.json:

parameters:
    # ...
    mailer.transport: sendmail

services:
    mailer:
        class:     Mailer
        arguments: ["%mailer.transport%"]
    newsletter_manager:
        class:     NewsletterManager
        calls:
            - [setMailer, ["@mailer"]]
Copier après la connexion
Copier après la connexion

En plus du principal ContainerInterface, le package container-interop définit également deux interfaces d'exception. Le premier est utilisé pour une exception régulière rencontrée lors de la création d'un service, et l'autre est utilisée lorsque le service demandé n'est pas trouvé. Nous ajouterons également une autre exception à cette liste lorsque le paramètre demandé n'est pas trouvé.

(Le contenu suivant omet la pièce d'implémentation du code parce que l'article est trop long et la logique principale a été décrite ci-dessus. Le code complet du référentiel GitHub contient l'implémentation complète des classes d'exception, des classes de référence et du conteneur classes.)

Résumé

Nous avons appris à créer un simple conteneur d'injection de dépendance, mais il existe de nombreux autres conteneurs qui ont des fonctionnalités puissantes que nous n'avons pas encore implémentées!

Certains conteneurs d'injection de dépendance, tels que PHP-DI et AURA.DI, fournissent une fonctionnalité appelée automatiquement. Ici, le conteneur devine quels services dans le conteneur doivent être injectés dans d'autres services. Pour ce faire, ils utilisent l'API de réflexion pour trouver des informations sur les paramètres du constructeur.

Vous pouvez dériver le référentiel comme vous le souhaitez et ajouter des fonctionnalités comme l'auto-assemblage, ce qui est un excellent exercice! De plus, nous conservons une liste publique de toutes les versions dérivées connues de ce conteneur afin que les autres puissent voir ce que vous faites. Partagez simplement votre travail avec nous en utilisant les commentaires ci-dessous et nous nous assurerons de l'ajouter.

Vous pouvez également nous contacter en utilisant les commentaires ci-dessous. Faites-nous savoir ce que vous voulez clarifier ou expliquer, ou toute erreur que vous trouvez.

(La section FAQS est omise car le contenu est fortement dupliqué à partir de ce qui précède et est trop long.)

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal