Maison >développement back-end >tutoriel php >PHP Master | Injection de dépendance avec bouton
Points de base
Dans le développement d'applications, nous essayons de créer des modules autonomes pour réutiliser le code dans les projets futurs. Cependant, la création de modules complètement indépendants qui fournissent des fonctionnalités utiles sont difficiles; C'est là que l'injection de dépendance est utile, car elle nous permet d'injecter les dépendances nécessaires pour que le code fonctionne correctement sans les coder dur dans le module. Pimple est un simple conteneur d'injection de dépendance qui utilise la fermeture de PHP pour définir les dépendances de manière gérable. Dans cet article, nous explorerons le problème des dépendances à code dur, comment l'injection de dépendance résout ces problèmes et comment utiliser Pimple pour faciliter l'injection de dépendance à la dépendance.
Problème de dépendances spécifiques
Lors de la rédaction d'applications, nous utilisons de nombreuses classes PHP. Une classe peut avoir besoin d'appeler des méthodes d'une ou plusieurs autres classes pour fournir les fonctionnalités attendues, nous disons donc que la première classe dépend d'autres classes. Par exemple:
<code class="language-php"><?php class A { public function a1() { $b = new B(); $b->b1(); } }</code>
La classe A dépend de la classe B. Si la classe B n'est pas disponible, le code ci-dessus ne fonctionnera pas. De plus, chaque fois que nous cocodions en dur la création d'un objet dans la classe, nous aurons des dépendances spécifiques à la classe. Les dépendances spécifiques sont un obstacle à la rédaction de code testable. Une meilleure approche consiste à fournir un objet de classe B à la classe A. Ces objets peuvent être fournis par le constructeur de A ou la méthode du secteur. Avant de discuter plus approfondie, regardons un scénario plus réaliste.
Partager du contenu sur les sites de réseaux sociaux est très courant de nos jours, et la plupart des sites Web affichent directement leurs flux de profil social sur leurs sites Web. Supposons que nous ayons une classe appelée SocialFeeds qui génère des flux à partir de sites sociaux tels que Twitter, Facebook, Google, etc. Créez des classes distinctes pour gérer chacun de ces services. Ici, nous examinerons la classe Twitterservice qui interagit avec Twitter. La classe SocialFeeds utilise Twitterservice pour demander des flux Twitter. Twiterservice interagit avec la base de données pour récupérer des jetons utilisateur spécifiques qui accèdent à l'API. Le jeton est transmis à la classe OAuth, qui récupère le flux à l'aide du jeton fourni et le renvoie à la classe SocialFeeds.
<code class="language-php"><?php class A { public function a1() { $b = new B(); $b->b1(); } }</code>
<code class="language-php"><?php class SocialFeeds { public function getSocialFeeds() { $twService = new TwitterService(); echo $twService->getTweets(); } }</code>
<code class="language-php"><?php class TwitterService { public function getTweets() { $db = new DB(); $query = "Query to get user token from database"; $token = $db->getQueryResults($query); $oauth = new OAuth(); return $oauth->requestTwitterFeed($token); } }</code>
<code class="language-php"><?php class OAuth { public function requestTwitterFeed($token) { // Retrieve and return twitter feed using the token } }</code>
Il est évident que SocialFeeds repose sur Twitterservice. Mais Twitterservice dépend de la DB et de l'OAuth, de sorte que SocialFeeds dépendent indirectement DB et OAuth. Alors, quel est le problème? Socialfeeds s'appuie sur la mise en œuvre concrète de trois classes, il est donc impossible de tester les sociaux-sociétés séparément sans la véritable mise en œuvre d'autres classes. Ou supposons que nous voulons utiliser une base de données différente ou un autre fournisseur OAuth. Dans ce cas, nous devons remplacer la classe existante par la nouvelle classe tout au long du code.
Correction des dépendances spécifiques
La solution à ces dépendances est simple, c'est-à-dire fournir dynamiquement des objets si nécessaire sans utiliser d'implémentations concrètes. Il existe deux types de techniques qui peuvent injecter des dépendances: l'injection de dépendance basée sur le constructeur et l'injection basée sur le secteur.
Injection basée sur le constructeur
En utilisant l'injection de dépendance basée sur le constructeur, l'objet de dépendance est créé à l'extérieur et passé comme paramètre au constructeur de la classe. Nous pouvons attribuer ces objets aux variables de classe et les utiliser n'importe où dans la classe. L'injection basée sur le constructeur de la classe SocialFeeds est la suivante:
<code class="language-php"><?php class DB { public function getQueryResults($query) { // Get results from database and return token } }</code>
Une instance de Twitterservice est passé comme un objet au constructeur. SocialFeeds repose toujours sur Twitterservice, mais maintenant nous sommes libres de fournir différentes versions des fournisseurs de services Twitter, et même des objets simulés à des fins de test. En ce qui concerne Twitterservice, les classes DB et OAuth sont également définies de la même manière.
<code class="language-php"><?php class SocialFeeds { public $twService; public function __construct($twService) { $this->twService = $twService; } public function getSocialFeeds() { echo $this->twService->getTweets(); } }</code>
injection basée sur le secteur
En utilisant l'injection basée sur le secteur, les objets sont fournis par des méthodes de setter au lieu des constructeurs. Ce qui suit est la mise en œuvre de l'injection de dépendance basée sur le setter de la classe SocialFeeds:
<code class="language-php"><?php $db = new DB(); $oauth = new OAuth(); $twService = new TwitterService($db, $oauth); $socialFeeds = new SocialFeeds($twService); $socialFeeds->getSocialFeeds();</code>
Le code d'initialisation comprend désormais DB et OAuth ressemble à ceci:
<code class="language-php"><?php class SocialFeeds { public $twService; public function getSocialFeeds() { echo $this->twService->getTweets(); } public function setTwitterService($twService) { $this->twService = $twService; } }</code>
Constructeur et injection de setter
Sélectionner l'injection basée sur le constructeur ou l'injection basée sur le secteur dépend de vous. L'injection basée sur le constructeur convient lorsque toutes les dépendances sont nécessaires pour instancier une classe. L'injection basée sur le secteur convient lorsque les dépendances ne sont pas nécessaires à chaque fois.
pros
Inconvénients
Le rôle de Pimple dans Di
Lorsque nous pouvons déjà injecter des dépendances en utilisant les techniques susmentionnées, vous vous demandez peut-être pourquoi vous avez besoin de bouton. Pour répondre à cette question, nous devons regarder le principe sec.
Ne vous répétez pas (sec) est un principe du développement logiciel qui vise à réduire la duplication de diverses informations, ce qui est particulièrement utile dans les architectures multicouches. L'énoncé du principe sec est que "chaque fragment de connaissance doit avoir une représentation unique, claire et faisant autorité dans un système" - WikipediaConsidérez l'exemple d'injection basé sur le constructeur. Chaque fois que nous voulons un objet de la classe SocialFeed, nous devons répéter l'intégralité du processus de configuration d'instanciation et de transmission de ses dépendances. Selon Dry, ce code doit être évité pour éviter les problèmes de maintenance. Pimple agit comme un conteneur qui définit ces dépendances pour éviter la duplication. Regardons un exemple simple pour voir comment fonctionne Pimple.
<code class="language-php"><?php class A { public function a1() { $b = new B(); $b->b1(); } }</code>Créez une instance de Pimple comme conteneur pour stocker les dépendances. Il implémente l'interface SPL ArrayAccess, donc l'utiliser est très similaire à l'utilisation des tableaux. Tout d'abord, nous définissons une clé qui contient le nom de toute classe que nous voulons. Nous définissons ensuite une fermeture pour renvoyer une instance de la classe spécifiée qui agit comme un service. Notez qu'une instance du conteneur sera transmise à $ C, nous pouvons donc nous référer à d'autres clés définies selon les besoins; chaque paramètre ou objet défini peut être utilisé dans la fermeture via la variable $ C. Maintenant, chaque fois que nous voulons une instance d'une classe, nous pouvons référencer la clé pour récupérer l'objet. Convertissons l'exemple SocialFeeds en pimple. Les exemples sur le site Web officiel du pimple montrent une injection basée sur le constructeur, nous allons donc ici illustrer l'injection basée sur le setter. N'oubliez pas que pour utiliser Pimple, nous n'avons pas besoin de modifier des méthodes de setter ou du code défini précédemment - nous encapsulons simplement la logique.
<code class="language-php"><?php class SocialFeeds { public function getSocialFeeds() { $twService = new TwitterService(); echo $twService->getTweets(); } }</code>Les classes DB et OAuth sont toutes deux des modules indépendants, nous retournons donc leurs nouvelles instances directement dans la fermeture. Nous utilisons ensuite l'injection basée sur le secteur pour ajouter des dépendances à la classe Twitterservice. Nous avons ajouté les classes DB et OAuth au conteneur, afin que nous puissions y accéder directement à l'intérieur de la fonction en utilisant $ c ['db'] et $ c ['oAuth']. Maintenant, les dépendances sont encapsulées dans le conteneur en tant que service. Chaque fois que nous voulons utiliser une classe DB différente ou un autre service OAuth, nous remplaçons simplement la classe dans l'instruction Container et tout fonctionnera parfaitement. Avec Pimple, il vous suffit d'ajouter de nouvelles dépendances en un seul endroit.
Utilisation avancée du pimp
Dans le scénario ci-dessus, Pimple renvoie une nouvelle instance de chaque classe de la fermeture à chaque fois qu'il est demandé. Dans certains cas, nous devons utiliser le même objet sans initialiser une nouvelle instance à chaque fois, comme la connexion à une base de données en est un exemple parfait. Pimple offre la possibilité de renvoyer la même instance à l'aide d'un objet partagé.
<code class="language-php"><?php class A { public function a1() { $b = new B(); $b->b1(); } }</code>Aussi, jusqu'à présent, nous avons défini toutes les dépendances dans un seul emplacement dans le conteneur Pimple. Cependant, considérons un cas où nous avons besoin d'un service qui a ses dépendances mais est configuré légèrement différemment du service d'origine. Par exemple, supposons que nous devons accéder à l'ORM pour implémenter certaines fonctionnalités de la classe Twitterservice. Nous ne pouvons pas modifier la fermeture existante car elle oblige toutes les fonctions existantes à utiliser ORM. PIMPLE fournit la méthode Extend () pour modifier dynamiquement les fermetures existantes sans affecter l'implémentation d'origine. Considérez le code suivant:
<code class="language-php"><?php class SocialFeeds { public function getSocialFeeds() { $twService = new TwitterService(); echo $twService->getTweets(); } }</code>Maintenant, nous pouvons utiliser différentes versions d'extension de Tweet_Service dans des cas spéciaux. Le premier paramètre est le nom du service, et le deuxième paramètre est une fonction qui peut accéder aux instances et aux conteneurs d'objets. En fait, Extend () est un moyen puissant d'ajouter dynamiquement les dépendances en fonction des différentes situations, mais assurez-vous de limiter la version étendue du service au minimum, car elle augmente la quantité de code en double.
Résumé
La gestion des dépendances est l'une des tâches les plus importantes et les plus difficiles du développement d'applications Web. Nous pouvons utiliser l'injection de dépendance des constructeurs et des méthodes de setter pour les gérer efficacement. Cependant, l'injection de dépendance elle-même a également quelques problèmes, et Pimple résout ces problèmes en fournissant un conteneur léger pour créer et stocker les dépendances d'objets de manière sèche. N'hésitez pas à partager votre expérience en gestion de dépendances dans votre projet et à vos réflexions sur Pimple en tant que conteneur d'injection de dépendance dans les commentaires ci-dessous.
FAQ sur l'injection de dépendance avec Pimple (FAQ)
Qu'est-ce que Pimple et pourquoi est-il utilisé en PHP?Comment fonctionne Pimple?
Comment installer Pimple?
. composer require pimple/pimple
Dans Pimple, vous pouvez définir un service en attribuant un objet appelant à une clé dans un conteneur. L'objet appelable doit renvoyer une instance du service. Par exemple, vous pouvez définir un service pour la classe d'expéditeur de messagerie comme ceci:
$container['mailer'] = function ($c) { return new Mailer($c['smtp']); };
Dans cet exemple, le service d'expéditeur de courrier est défini comme une nouvelle instance de la classe Mailer, où le service SMTP est injecté comme une dépendance.
Vous pouvez accéder aux services dans Pimple à l'aide de la notation du tableau avec des clés de service. Par exemple, vous pouvez accéder au service d'expéditeur de messagerie comme ceci: $mailer = $container['mailer'];
. Lorsque vous accédez à un service, Pimple exécute la définition de service et renvoie l'objet de service.
Par défaut, Pimple renvoie une nouvelle instance du service chaque fois qu'il accède au service. Si vous souhaitez partager le service et renvoyer la même instance à chaque fois, vous pouvez utiliser la méthode share()
. Par exemple, vous pouvez partager le service d'expéditeur de messagerie comme ceci: $container['mailer'] = $container->share(function ($c) { return new Mailer($c['smtp']); });
.
Oui, vous pouvez utiliser la méthode extend()
pour étendre les services dans Pimple. Cela vous permet de modifier le service après l'avoir défini. Par exemple, vous pouvez étendre le service d'expéditeur de messagerie comme celui-ci pour ajouter une configuration supplémentaire:
$container['mailer'] = $container->extend('mailer', function ($mailer, $c) { $mailer->setFrom($c['email.from']); return $mailer; });
Dans cet exemple, la méthode setFrom()
est appelée sur le service d'expéditeur de courrier à l'aide du service email.from
comme paramètre.
Dans Pimple, vous pouvez utiliser la méthode protect()
pour protéger les paramètres (qui ne doivent pas être considérés comme des paramètres des services). Cela vous permet de stocker des valeurs dans un conteneur sans les traiter comme des définitions de service. Par exemple, vous pouvez protéger la valeur de configuration comme ceci: $container['config.value'] = $container->protect(function () { return 'value'; });
.
Vous pouvez utiliser Pimple dans un projet en créant une nouvelle instance de la classe Pimplicontainer et en définissant un service là-bas. Vous pouvez ensuite accéder au service à partir du conteneur où vous en avez besoin dans l'application. Cela vous permet de gérer les services de manière centralisée et de les injecter dans différentes parties de votre application.
Pimple offre de nombreux avantages pour le développement de PHP. Il rend votre code plus flexible car il vous permet de gérer les services de manière centralisée. Il rend votre code plus facile à réutiliser car il vous permet de partager des services tout au long de votre application. Il rend votre code plus facile à tester car il vous permet d'injecter des services simulés pour les tests. En utilisant Pimple, vous pouvez améliorer la qualité de votre code et faciliter le maintien et le test.
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!