Foire aux questions sur la DI (FAQ)
- DI est-il un autre nom pour IoC ?
- Qu'est-ce que le Service Locator ?
- Quand est-il préférable de ne pas utiliser la DI ?
- L'utilisation de la DI a-t-elle des inconvénients ?
- Comment réécrire une application legacy en DI ?
- Pourquoi la composition est-elle préférée à l'héritage ?
- Peut-on utiliser le conteneur Nette DI en dehors de Nette ?
- Pourquoi la configuration est-elle dans des fichiers NEON ?
- L'analyse des fichiers NEON ralentit-elle l'application ?
- Comment accéder aux paramètres du fichier de configuration depuis ma classe ?
- Nette supporte-t-il PSR-11 : Container interface ?
DI est-il un autre nom pour IoC ?
L'Inversion de Contrôle (IoC) est un principe axé sur la manière dont le code est exécuté – si votre code
exécute du code étranger ou si votre code est intégré dans du code étranger qui l'appelle ensuite. IoC est un terme large
englobant les événements, ce qu'on appelle le principe d'Hollywood et d'autres aspects. Les
factories, dont parle la Règle n°3 : laissez faire
la factory, font également partie de ce concept et représentent une inversion pour l'opérateur new
.
L'Injection de Dépendances (DI) se concentre sur la manière dont un objet prend connaissance d'un autre objet, c'est-à-dire de ses dépendances. C'est un patron de conception qui exige le passage explicite des dépendances entre les objets.
On peut donc dire que la DI est une forme spécifique d'IoC. Cependant, toutes les formes d'IoC ne sont pas appropriées du point de vue de la propreté du code. Par exemple, parmi les anti-patrons figurent les techniques qui travaillent avec l'état global ou ce qu'on appelle le Service Locator.
Qu'est-ce que le Service Locator ?
C'est une alternative à l'Injection de Dépendances. Il fonctionne en créant un dépôt central où tous les services ou dépendances disponibles sont enregistrés. Lorsqu'un objet a besoin d'une dépendance, il la demande au Service Locator.
Cependant, par rapport à l'Injection de Dépendances, il perd en transparence : les dépendances ne sont pas passées directement aux objets et ne sont donc pas facilement identifiables, ce qui nécessite d'examiner le code pour découvrir et comprendre toutes les liaisons. Les tests sont également plus complexes, car nous ne pouvons pas simplement passer des objets mock aux objets testés, mais nous devons passer par le Service Locator. De plus, le Service Locator perturbe la conception du code, car les objets individuels doivent connaître son existence, ce qui diffère de l'Injection de Dépendances, où les objets n'ont pas connaissance du conteneur DI.
Quand est-il préférable de ne pas utiliser la DI ?
Aucune difficulté connue n'est associée à l'utilisation du patron de conception Injection de Dépendances. Au contraire, l'obtention de dépendances à partir d'emplacements globalement disponibles entraîne toute une série de complications, tout comme l'utilisation du Service Locator. Il est donc conseillé d'utiliser toujours la DI. Ce n'est pas une approche dogmatique, mais simplement aucune meilleure alternative n'a été trouvée.
Néanmoins, il existe certaines situations où nous ne passons pas d'objets et les obtenons depuis l'espace global. Par exemple, lors du débogage de code, lorsque vous devez afficher la valeur d'une variable à un point spécifique du programme, mesurer la durée d'une certaine partie du programme ou enregistrer un message. Dans de tels cas, lorsqu'il s'agit d'actions temporaires qui seront ultérieurement supprimées du code, il est légitime d'utiliser un dumper, un chronomètre ou un logger globalement disponible. Ces outils ne font en effet pas partie de la conception du code.
L'utilisation de la DI a-t-elle des inconvénients ?
L'utilisation de l'Injection de Dépendances entraîne-t-elle des inconvénients, tels qu'une complexité accrue de l'écriture du code ou une dégradation des performances ? Que perdons-nous lorsque nous commençons à écrire du code conformément à la DI ?
La DI n'a pas d'impact sur les performances ou l'utilisation de la mémoire de l'application. Les performances du conteneur DI peuvent jouer un certain rôle, mais dans le cas de Nette DI, le conteneur est compilé en PHP pur, de sorte que sa surcharge lors de l'exécution de l'application est pratiquement nulle.
Lors de l'écriture du code, il est parfois nécessaire de créer des constructeurs acceptant des dépendances. Auparavant, cela pouvait être fastidieux, mais grâce aux IDE modernes et à la promotion des propriétés du constructeur, c'est maintenant une question de quelques secondes. Les factories peuvent être facilement générées à l'aide de Nette DI et du plugin pour PhpStorm en un clic de souris. D'un autre côté, il n'est plus nécessaire d'écrire des singletons et des points d'accès statiques.
On peut affirmer qu'une application correctement conçue utilisant la DI n'est ni plus courte ni plus longue qu'une application utilisant des singletons. Les parties du code travaillant avec des dépendances sont simplement extraites des classes individuelles et déplacées vers de nouveaux emplacements, c'est-à-dire dans le conteneur DI et les factories.
Comment réécrire une application legacy en DI ?
La transition d'une application legacy vers l'Injection de Dépendances peut être un processus exigeant, en particulier pour les applications volumineuses et complexes. Il est important d'aborder ce processus de manière systématique.
- Lors de la transition vers l'Injection de Dépendances, il est important que tous les membres de l'équipe comprennent les principes et les procédures utilisés.
- Commencez par analyser l'application existante et identifier les composants clés et leurs dépendances. Créez un plan indiquant quelles parties seront refactorisées et dans quel ordre.
- Implémentez un conteneur DI ou, mieux encore, utilisez une bibliothèque existante, telle que Nette DI.
- Refactorisez progressivement les différentes parties de l'application pour utiliser l'Injection de Dépendances. Cela peut inclure la modification des constructeurs ou des méthodes pour accepter les dépendances comme paramètres.
- Modifiez les endroits du code où les objets avec des dépendances sont créés, afin que les dépendances soient injectées par le conteneur à la place. Cela peut inclure l'utilisation de factories.
N'oubliez pas que la transition vers l'Injection de Dépendances est un investissement dans la qualité du code et la maintenabilité à long terme de l'application. Bien qu'il puisse être difficile d'apporter ces changements, le résultat devrait être un code plus propre, plus modulaire et facilement testable, prêt pour les extensions et la maintenance futures.
Pourquoi la composition est-elle préférée à l'héritage ?
Il est préférable d'utiliser la composition plutôt que l'héritage, car elle sert à réutiliser le code sans avoir à se soucier des conséquences des changements. Elle offre donc un couplage plus lâche, où nous n'avons pas à craindre que la modification d'un code n'entraîne la nécessité de modifier un autre code dépendant. Un exemple typique est la situation appelée enfer du constructeur.
Peut-on utiliser le conteneur Nette DI en dehors de Nette ?
Absolument. Le conteneur Nette DI fait partie de Nette, mais il est conçu comme une bibliothèque autonome qui peut être utilisée indépendamment des autres parties du framework. Il suffit de l'installer à l'aide de Composer, de créer un fichier de configuration avec la définition de vos services, puis d'utiliser quelques lignes de code PHP pour créer le conteneur DI. Et vous pouvez immédiatement commencer à profiter des avantages de l'Injection de Dépendances dans vos projets.
L'utilisation concrète, y compris les codes, est décrite dans le chapitre Conteneur Nette DI.
Pourquoi la configuration est-elle dans des fichiers NEON ?
NEON est un langage de configuration simple et facile à lire, développé dans le cadre de Nette pour configurer les applications, les services et leurs dépendances. Par rapport à JSON ou YAML, il offre des possibilités beaucoup plus intuitives et flexibles à cet effet. En NEON, on peut décrire naturellement des liaisons qui seraient impossibles à écrire en Symfony & YAML, ou seulement au moyen d'une description complexe.
L'analyse des fichiers NEON ralentit-elle l'application ?
Bien que les fichiers NEON soient analysés très rapidement, cet aspect n'a aucune importance. La raison en est que l'analyse des fichiers n'a lieu qu'une seule fois lors du premier lancement de l'application. Ensuite, le code du conteneur DI est généré, enregistré sur le disque et exécuté à chaque requête ultérieure, sans qu'il soit nécessaire d'effectuer d'autres analyses.
C'est ainsi que cela fonctionne dans un environnement de production. Pendant le développement, les fichiers NEON sont analysés chaque fois que leur contenu est modifié, afin que le développeur dispose toujours d'un conteneur DI à jour. L'analyse elle-même est, comme mentionné, une question d'instant.
Comment accéder aux paramètres du fichier de configuration depuis ma classe ?
Gardons à l'esprit la Règle n°1 : faites-vous le passer. Si une classe nécessite des informations du fichier de configuration, nous n'avons pas besoin de réfléchir à la manière d'accéder à ces informations, nous les demandons simplement – par exemple, via le constructeur de la classe. Et nous effectuons le passage dans le fichier de configuration.
Dans cet exemple, %myParameter%
est un placeholder pour la valeur du paramètre myParameter
, qui est
passée au constructeur de la classe MyClass
:
# config.neon
parameters:
myParameter: Some value
services:
- MyClass(%myParameter%)
Si vous souhaitez passer plusieurs paramètres ou utiliser l'autowiring, il est conseillé d'encapsuler les paramètres dans un objet.
Nette supporte-t-il PSR-11 : Container interface ?
Le conteneur Nette DI ne prend pas en charge PSR-11 directement. Cependant, si vous avez besoin d'interopérabilité entre le conteneur Nette DI et des bibliothèques ou des frameworks qui attendent une interface de conteneur PSR-11, vous pouvez créer un simple adaptateur qui servira de pont entre le conteneur Nette DI et PSR-11.