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.
Points clés:
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. 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); }
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"]]
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')));
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); }
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"]]
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!