Et si le travail du dispatcher était fait avant même la première requête ?
Chaque requête HTTP traitée par une application Symfony démarre par une phase de préparation que l'on remarque rarement. Parmi ces étapes figure la construction du répartiteur d'événements (l'EventDispatcher), le composant qui relie les événements du noyau, de Doctrine ou de votre code métier aux écouteurs et abonnés qui doivent réagir. Avec Symfony 8.2, cette mécanique évolue : le répartiteur devient compilé. Voici ce que l'on peut en retenir, et comment vous préparer.
Le fonctionnement actuel : une construction à l'exécution
Aujourd'hui, le répartiteur est créé à l'exécution, à chaque requête. Le conteneur d'injection de dépendances instancie le service, puis appelle addListener() pour chaque écouteur déclaré. Les écouteurs sont enregistrés un par un, avec leur priorité, avant que le moindre événement puisse être dispatché.
Pris isolément, ce coût est faible. Mais il se répète à chaque requête, et il grandit avec le nombre d'écouteurs et d'abonnés : le noyau en enregistre déjà plusieurs, les bundles tiers en ajoutent, et votre application aussi. Sur un projet de taille moyenne, il s'agit de nombreux appels qui produisent à chaque fois le même résultat, puisque la liste des écouteurs ne change pas entre deux requêtes en production.
L'idée du répartiteur compilé
La fonctionnalité, portée par Nicolas Grekas à travers plusieurs pull requests (#66122, #66129, #66131 et #66133), s'inscrit dans l'effort général de performance de Symfony 8.2. Le principe : puisque la configuration des écouteurs est connue au moment de la compilation du conteneur, autant déplacer ce travail à ce moment-là plutôt que de le refaire à chaque requête.
En pratique, cela revient à pré-calculer la structure du répartiteur une seule fois, lors du warmup du cache, afin que l'exécution n'ait plus qu'à l'utiliser. C'est la même logique qui a déjà guidé d'autres optimisations de Symfony : tout ce qui est déterministe est résolu en amont, et le runtime ne fait que le strict nécessaire.
Ce que cela change pour une application :
- moins de travail d'initialisation à chaque requête ;
- un gain qui augmente avec le nombre d'écouteurs enregistrés ;
- un comportement fonctionnel censé rester identique, puisqu'il s'agit d'une optimisation interne.
L'article source ne détaille pas ici de mesures chiffrées, et nous n'en avançons donc aucune. Le bénéfice réel dépendra de votre projet, et seul un profilage de votre application le dira.
Ce qu'il faut vérifier avant de migrer
Une optimisation qui pré-calcule la configuration pose toujours la même question : que devient ce qui est dynamique ? Avant de passer à Symfony 8.2, voici les points à passer en revue dans votre code :
- Les écouteurs ajoutés à la volée. Si du code appelle
addListener()ouaddSubscriber()sur le répartiteur après sa création (dans un test, un script ou un service d'infrastructure), vérifiez que ce cas reste supporté par la version compilée. - Les décorateurs du service. Si vous décorez
event_dispatcher(pour du tracing ou de l'instrumentation, par exemple), contrôlez que votre décorateur continue de se brancher correctement. - Les tests. Une suite de tests solide, avec quelques tests qui vérifient que vos écouteurs critiques sont bien déclenchés dans le bon ordre, reste le meilleur filet de sécurité.
- Le warmup en déploiement. Comme le travail se fait à la compilation, assurez-vous que votre pipeline de déploiement réchauffe bien le cache (
cache:warmup) en environnement de production, et qu'il ne laisse pas ce coût à la première requête.
Ces points relèvent de la prudence habituelle face à un changement interne. Le détail exact de l'API et des éventuelles options de configuration se trouve dans les pull requests citées et dans la documentation de la version.
Comment s'y préparer dès maintenant
Symfony 8.2 n'est pas encore sortie : il est donc inutile de précipiter une migration. En revanche, plusieurs actions peuvent être menées dès aujourd'hui pour être prêt le jour J :
- Faire l'inventaire de vos écouteurs et abonnés (la commande
debug:event-dispatcherest faite pour cela) afin de repérer ceux qui sont atypiques. - Mettre en place un profilage de référence (avec Blackfire, le profiler Symfony ou un outil équivalent) pour pouvoir comparer avant et après.
- Tester la branche de développement ou les versions préliminaires sur un environnement de préproduction, pas sur la production.
- Suivre les notes de migration de la version, qui indiqueront les changements de comportement éventuels.
En résumé
Le répartiteur d'événements compilé est typiquement le genre d'amélioration que Symfony sait bien faire : une optimisation discrète, qui déplace du travail répété vers la phase de compilation et qui n'exige, idéalement, aucune modification de votre code. Elle vient compléter les autres gains de performance annoncés pour la 8.2. Le plus sage est de mesurer votre situation actuelle, de repérer les usages dynamiques du répartiteur, puis de tester la nouvelle version dès qu'elle est disponible.
Pour aller plus loin, consultez l'annonce originale : New in Symfony 8.2: Compiled Event Dispatcher.
Et votre site, il vaut quoi ?
Vitesse, accessibilité, référencement technique. Le rapport est écrit pour un dirigeant, pas pour un développeur. Gratuit, sans inscription.