La plupart des cadres et des applications PHP plus grandes utilisent un conteneur d'injection de dépendance dans le but d'une base de code plus maintenable. Cependant, cela peut avoir un impact sur les performances. Comme les temps de chargement comptent, garder les sites rapidement est important comme jamais. Aujourd'hui, je vais comparer plusieurs conteneurs d'injection de dépendance PHP pour voir à quoi ressemblent leurs performances relatives.
Pour ceux qui ne connaissent pas le concept, un conteneur d'injection de dépendance est un logiciel qui construit automatiquement un arbre d'objet. Par exemple, considérez un objet utilisateur qui nécessite une instance de base de données.
<span>$user = new User(new Database());</span>
Un conteneur d'injection de dépendance peut être utilisé pour construire automatiquement l'arbre d'objet sans avoir besoin de fournir les paramètres manuellement:
<span>$user = $container->get('User');</span>
Chaque fois que cela s'appelle, un objet utilisateur sera créé avec l'objet de base de données «injecté».
Il existe plusieurs conteneurs bien connus (et pas si bien connus) disponibles pour PHP:
un mot sur Pimple: Bien que Pimple soit annoncé comme un conteneur d'injection de dépendance, la récupération d'un objet du conteneur renvoie toujours la même instance, ce qui fait du pimple un localisateur de service plutôt que comme un conteneur d'injection de dépendance et ne peut pas, en tant que tel, ne peut pas être testé.
Bien que tous les conteneurs prennent en charge différentes fonctionnalités, cette référence couvrira les fonctionnalités de base requises par un conteneur d'injection de dépendance. Autrement dit, créer des objets et injecter des dépendances là où ils sont nécessaires.
Tous les tests ont été exécutés sur la même machine exécutant Arch Linux (3,15 noyau), PHP 5.5.13 et les dernières versions de chaque conteneur au 03/07/2014.
Tous les numéros de temps d'exécution présentés sont en moyenne 10 cycles après avoir jeté ceux qui dépassent 20% plus lents que les plus rapides.
Ce test utilise chaque conteneur pour créer un objet simple 10 000 fois
Sans conteneur d'injection de dépendance, cela serait écrit comme suit:
<span>$user = new User(new Database());</span>
Code de test (sur github): aura, dés, ornodi, php-di, symfonydependencyInjection, zenddi
Comme vous pouvez le voir, il y a deux camps clairs ici. Aura, Dice et Orno étant environ dix fois plus rapides que PHP-DI, Symfony et Zenddi.
Similaire au temps d'exécution, il y a deux groupes distincts avec Symfony assis quelque part sur le terrain.
Cela est très révélateur de la légèreté de chaque conteneur et explique en quelque sorte les différences d'utilisation de la mémoire. Il convient de noter que beaucoup de fichiers utilisés par Zenddi sont des fichiers de framework commun, donc si vous utilisez Zend Framework, alors l'utilisation de Zenddi n'enverra pas les mêmes frais généraux de mémoire que les fichiers seront probablement réutilisés ailleurs dans votre application.
De même, PHP-DI s'appuie fortement sur les bibliothèques de doctrine. Si vous utilisez la doctrine dans votre projet, les frais généraux de mémoire de PHP-DI sont réduits.
Cependant, il est agréable de voir que SymfonyDependencyInjection, bien qu'il fasse partie de la pile de framework est entièrement autonome et fonctionne sans dépendances d'autres projets Symfony.
AURA, DICE et ORNO n'ont pas de dépendances externes et cela aide à réduire leurs comptes de fichiers.
Étant donné que les fichiers de chargement peuvent avoir un impact sur les performances et que Zend et PHP-DI ont chargé un nombre significatif de fichiers, le même test a été effectué en ignorant le temps d'autoloder en créant d'abord une seule instance de la classe, garantissant que toutes les classes requises étaient automatique le temps.
Cela peut également avoir déclenché toute mise en cache interne effectuée par le conteneur, mais le même traitement a été appliqué à chaque conteneur pour le garder juste
Code PHP équivalent:
<span>$user = new User(new Database());</span>
Code de test (sur github): aura, dés, ornodi, php-di, symfonydependencyInjection, zenddi
Comme prévu, l'utilisation de la mémoire est inchangée et les performances sont légèrement meilleures car le temps d'autoloder n'est pas mesuré. Cependant, cela montre que PHP-DI, même le chargement de 42 fichiers a un impact négligeable sur le temps d'exécution total et les performances relatives restent les mêmes, le chargement des dizaines de fichiers n'est pas la cause de PHP-DI et Zenddi ayant des performances relativement lentes.
Même après avoir ignoré la surcharge des fichiers de chargement, il y a encore deux terrains de balle distincts ici. Aura, Dice et Orno sont très similaires dans les performances et l'utilisation de la mémoire tandis que PHP-DI, Zend et Symfony ne sont en concurrence que les uns avec les autres.
Tous les tests à l'avenir ignoreront le temps de mise à jour pour s'assurer qu'il s'agit vraiment des performances du conteneur qui sont mesurées.
Ce test est effectué en faisant construire les conteneurs de cet ensemble d'objets 10 000 fois:
<span>$user = $container->get('User');</span>
Code de test (sur github): aura, dés, ornodi, php-di, symfonydependencyInjection, zenddi
Remarque: Comme vous pouvez le voir en regardant le code de test, Symfony, PHP-DI et AURA nécessitent beaucoup plus de code de configuration que les autres conteneurs pour effectuer ce test. Le temps de configuration n'a pas été inclus dans le test.
Encore une fois, il y a très peu de différence entre le top 3, avec des dés 20% plus rapides qu'aura et 70% plus rapidement qu'Orno. Tous les trois sont considérablement plus rapides que Zend, PHP-DI et Symfony. La différence entre les trois conteneurs supérieurs est si faible en termes réels que vous ne remarqueriez jamais la différence de vitesse en dehors d'une référence artificielle comme celle-ci.
zend, php-di et, dans une moindre mesure, Symfony sont lents ici. Zend prend 37 secondes pour effectuer une tâche que les dés gère en moins de 1 seconde; Certainement pas une différence triviale. Encore une fois, Symfony prend les devants parmi les grands conteneurs.
La mémoire et le nombre de fichiers sont cohérents avec ce que nous avons vu dans d'autres tests.
DI Les conteneurs doivent également stocker et récupérer des services qui seront réutilisés tout au long de l'application. Ce test récupère une seule instance du conteneur à plusieurs reprises.
Équivalent pur PHP:
<span>$user = new User(new Database());</span>
Code de test (sur github): aura, dés, ornodi, php-di, symfonydependencyInjection, zenddi
Ceci est inattendu en fonction des résultats précédents. Tous les conteneurs sauf Zend et Symfony sont à peu près égaux avec seulement 0,01 s séparant les 4 premiers résultats. Symfony n'est pas loin derrière, mais Zend est bien plus de dix fois plus lent que les autres.
L'utilisation de la mémoire et le nombre de résultats de fichiers deviennent prévisibles avec la même division entre les conteneurs que nous avons vus en temps d'exécution.
Le test final consiste à voir à quelle vitesse un objet peut être construit et à injecter un service. Cela prend le format:
<span>$user = $container->get('User');</span>
Code de test (sur github): aura, dés, ornodi, php-di, symfonydependencyInjection, zenddi
Fait intéressant, Aura a pris une légère avance dans ce test. Cependant, ce n'est pas tout à fait un test comme à type pour Symfony et Aura nécessite plusieurs lignes de configuration explicite tandis que les autres conteneurs résolvent automatiquement la dépendance. Le temps pris pour configurer le conteneur ne faisait pas partie de la référence.
Étonnamment, PHP-DI est le plus lent à cette tâche, Zend prenant sa position devant PHP-DI et Symfony pour la première fois.
Sur la seule performance, les dés, l'aura et l'orno sont tous des concurrents solides, les dés sont le plus rapide dans l'ensemble et l'aura le plus rapide dans le test final. La différence entre les deux groupes distinctes est apparente mais il est intéressant de comparer les caractéristiques de chaque conteneur. Le nombre de fonctionnalités et de performances ne sont pas tout à fait corrélés comme vous vous en doutez. PHP-DI et DICE contiennent des fonctionnalités uniques, mais PHP-DI prend un coup de performance lourd pour le faire. Aura, bien que rapide, nécessite beaucoup de configuration manuelle et, comme vous vous en doutez, a des fonctionnalités très minimes tandis que les dés et Orno ont des performances très similaires mais nécessitent beaucoup moins de code pour configurer.
Symfony est vraiment dans le terrain du milieu dans tous les tests, bien que la configuration, comme avec Aura, soit une tâche beaucoup plus difficile car aucun type de support n'a fait naître des paramètres. Si vous recherchez un conteneur à partir d'un projet bien connu, Symfony doit être le conteneur de choix si les performances sont importantes.
Cela dit, si les performances pures sont ce que vous recherchez, les dés et Aura sont les gagnants clairs avec Orno très près. Cependant, il vaut la peine de jeter un œil à la syntaxe de configuration et aux fonctionnalités de chacun pour voir avec quoi vous préféreriez travailler comme différence de performance entre les dés, l'aura et l'orno est négligeable pour toute application réelle.
Tout le code des tests est disponible sur GitHub. Veuillez noter: le référentiel GitHub contient des copies des bibliothèques testées plutôt que d'utiliser composer pour les inclure dans le projet, c'est pour vous assurer que vous pouvez exécuter le code avec les versions exactes que j'ai testées et obtenir les mêmes résultats.
Les références de performance des conteneurs d'injection de dépendance PHP sont cruciales pour comprendre l'efficacité et la vitesse de différents conteneurs d'injection de dépendance. Ces repères fournissent une analyse comparative de divers conteneurs, aidant les développeurs à prendre des décisions éclairées sur le conteneur à utiliser en fonction de leurs besoins spécifiques. Ils offrent un aperçu des performances de chaque conteneur en termes d'utilisation de la mémoire et de consommation de temps, qui sont des facteurs critiques pour optimiser les performances des applications PHP.
L'injection de dépendance (DI) dans PHP améliore la qualité du code en favorisant le couplage lâche, en améliorant la testabilité et en augmentant la réutilisabilité du code. En injectant les dépendances, les composants deviennent plus indépendants, ce qui rend le code plus facile à modifier et à tester. Il encourage également le principe de responsabilité unique car chaque classe ne fait que ce qu'elle est censée faire, conduisant à un code plus propre et plus maintenable.
Il existe trois principaux types d'injection de dépendance dans PHP: injection de constructeur, injection de setter et injection d'interface. L'injection du constructeur est l'endroit où les dépendances sont fournies par un constructeur de classe. L'injection de setter implique de fournir les dépendances via des méthodes. L'injection d'interface nécessite que la classe dépendante implémente une interface qui injectera la dépendance.
Un conteneur d'injection de dépendance dans PHP, également connu sous le nom de service Conteneur, gère l'instanciation et la configuration des services ou des objets dans une application. Il agit comme une usine responsable de la création et du retour des cas de dépendances. Il gère également les instances partagées, en s'assurant qu'une seule instance est renvoyée à chaque fois qu'un service partagé est demandé.
Lors du choix d'une injection de dépendance Conteneur, considérez des facteurs tels que la facilité d'utilisation, les performances, le soutien communautaire et la compatibilité avec votre projet. Les performances sont particulièrement importantes, et c'est là que les repères de performance des conteneurs de dépendance de dépendance PHP sont utiles. Ils fournissent une analyse comparative des performances de divers conteneurs, vous aidant à prendre une décision éclairée.
L'injection de dépendance facilite les tests en découplant le découplage le dépendances d'une classe. Cela permet aux dépendances d'être moquées ou de talon pendant les tests, vous permettant de tester les classes isolément. Il facilite également la rédaction de tests unitaires, car vous pouvez injecter des dépendances simulées qui fournissent des réponses prévisibles, ce qui rend vos tests plus fiables et plus faciles à écrire.
Oui, l'injection de dépendance peut être utilisée dans n'importe quel projet PHP, quelle que soit sa taille ou sa complexité. C'est un modèle de conception qui favorise la réutilisabilité du code, la modularité et la testabilité, ce qui en fait un outil précieux pour tout développeur PHP.
Pendant l'injection de dépendance Peut introduire une légère surcharge en raison de la couche d'abstraction supplémentaire, l'impact sur les performances de l'application est généralement négligeable. Les avantages de l'amélioration de la qualité du code, de la testabilité et de la maintenabilité l'emportent souvent sur les coûts de performance mineurs.
La dépendance est étroitement liée aux principes solides, en particulier le principe d'inversion de dépendance (DIP). La DIP indique que les modules de haut niveau ne devraient pas dépendre de modules de bas niveau, mais les deux devraient dépendre d'abstractions. L'injection de dépendance permet cela en vous permettant d'injecter des dépendances sous forme d'interfaces ou de classes abstraites, plutôt que de classes concrètes.
Bien qu'il soit techniquement Possible d'utiliser plusieurs conteneurs d'injection de dépendance dans un seul projet PHP, il n'est généralement pas recommandé. L'utilisation de plusieurs conteneurs peut conduire à un code plus difficile à gérer et à comprendre. Il est généralement préférable de choisir un conteneur qui correspond le mieux aux besoins de votre projet et de s'en tenir.
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!