Tous les articles
Ven. 28 novembre 2025 · 5 min de lecture

🎼 Symfony 8.0 : nouvelle majeure, PHP 8.4 mini, UUID v7 par défaut, XML déprécié

Symfony 8.0

📚 Introduction

Symfony 8.0 est sorti en novembre 2025, en même temps que 7.4. Comme à chaque nouveau cycle pair, on franchit un palier PHP : le minimum passe à PHP 8.4. Le reste suit la philosophie maintenant bien rodée de l’équipe : pas de table rase, mais des fondations rangées et quelques choix par défaut modernisés.

J’écris ce post avec le recul de quelques mois de production. C’est l’occasion de revenir sur ce qui change réellement quand on bascule un projet 7.x vers 8.0, et ce qui justifie de planifier la migration plutôt que de rester sur 7.4 (qui partage les mêmes features mais reste en PHP 8.2).

🎯 PHP 8.4 comme socle

C’est le changement structurant. Symfony 8.0 exige PHP 8.4 minimum. Ça veut dire que tu peux compter sur :

  • Les property hooks dans tes Resources et tes DTOs (utile pour calculer des valeurs dérivées sans méthode dédiée).
  • Le mode lazy des objets, qui marche maintenant en standard et que Doctrine commence à exploiter.
  • Les array_find, array_find_key, array_all, array_any qui rendent les collections de Symfony et de Doctrine moins fragmentaires.

Si tu maintiens un projet 7.x sur du PHP 8.2 ou 8.3, c’est l’occasion de planifier la double mise à jour : runtime puis framework. Sur des CI propres (GitHub Actions pour Laravel et Symfony), c’est une question de quelques heures.

🧬 UUID v7 par défaut (et c’est bien)

Avant 8.0, le UuidV4 était la valeur par défaut générée par Symfony\Component\Uid\Uuid::v4()-style helpers. Désormais, la méthode utilitaire de référence est Uuid::v7() : UUID séquentiels horodatés, beaucoup plus sympathiques en index B-Tree.

use Symfony\Component\Uid\Uuid;
 
$id = Uuid::v7();

L’incidence sur la base de données est réelle. Sur Postgres ou MySQL, indexer une colonne UUID v4 produit des inserts aléatoires (fragmentation du B-Tree). UUID v7 maintient l’ordre temporel et donne des performances proches d’un BIGINT auto-incrémenté, tout en gardant l’anti-énumération côté API.

Si ton projet stocke des UUIDs en BINARY(16) ou en uuid natif, aucun changement à prévoir. Si tu te bases sur du tri par ID pour des paginations, regarde si le passage à v7 ne change pas l’ordre des nouveaux enregistrements.

🧱 Config PHP en array (et XML déprécié)

Deux mouvements liés :

  1. La configuration fluent en PHP ($services->set(...)->args(...)) est officiellement remplacée par un format array beaucoup plus lisible et qui s’autocomplète bien dans les IDE :
use Symfony\Config\FrameworkConfig;
 
return static function (FrameworkConfig $config): void {
	$config->session()
		->handlerId('session.handler.native_file')
		->cookieSamesite('lax');
 
	$config->mailer()
		->dsn(env('MAILER_DSN'));
};
  1. XML comme format de config est déprécié. Tu peux encore l’utiliser, mais les exemples officiels et les bundles modernes passent désormais en YAML ou en PHP. Si tu démarres un projet aujourd’hui, prends PHP. Le static analysis suit, le refactoring suit, et tu n’auras plus à choisir entre <argument type="service"> et autres curiosités XML.

Pour migrer un legacy chargé en XML, un outil comme rector aide bien à transformer en YAML ou en PHP.

🛠️ Console : enum, DTO, prompts

Les invokable commands progressent encore. Tu peux maintenant :

  • Recevoir un enum en argument et laisser Symfony résoudre la valeur :
enum Channel: string
{
	case Email = 'email';
	case Sms = 'sms';
	case Push = 'push';
}
 
#[AsCommand('app:notify')]
final class NotifyCommand
{
	public function __invoke(User $user, Channel $channel): int
	{
		// $channel est déjà une instance d'enum, pas une string
		return Command::SUCCESS;
	}
}
  • Passer un DTO typé en argument, populé depuis les options.
  • Utiliser des prompts interactifs propres, sans bidouiller avec QuestionHelper.
  • Tester tout ça sans monter de CommandTester complexe.

C’est du polish, mais à force d’écrire des commandes Symfony pendant des années, je remarque enfin la différence. Le code est plus court et plus lisible. Voir aussi Laravel Pail pour la même tendance côté Laravel.

🌐 HttpClient avec cache RFC 9111

Le composant HttpClient gagne une couche de cache HTTP conforme RFC 9111. Concrètement, les en-têtes Cache-Control, ETag, Vary sont respectés côté client. Tu peux donc empiler un cache local devant n’importe quelle API :

use Symfony\Component\HttpClient\CachingHttpClient;
use Symfony\Component\HttpKernel\HttpCache\Store;
 
$store = new Store('/var/cache/http');
$client = new CachingHttpClient(HttpClient::create(), $store);

Pour les apps qui consomment beaucoup d’APIs publiques (météo, géocodage, OpenAI…), c’est une économie de coût et de latence immédiate quand les endpoints exposent des Cache-Control honnêtes.

📨 Messenger : signature des messages

Les messages Messenger peuvent désormais être signés avant d’être placés sur le transport. À la consommation, la signature est vérifiée. C’est un garde-fou utile dans les architectures où le bus de messages traverse une infra non-trustée (RabbitMQ partagé avec d’autres équipes, Redis multi-tenant).

Si tu utilises déjà Messenger en prod, j’en ai parlé dans Symfony Messenger : exécuter des jobs asynchrones proprement. L’activation se fait dans messenger.yaml et est rétro-compatible : tu peux la déployer sans casser les messages en cours.

🪜 Multi-step forms

C’est ma préférée. Les form flows débarquent enfin nativement. Plus besoin du bundle craue/formflow-bundle qu’on traîne depuis des années pour gérer un wizard d’inscription en 4 étapes. Symfony fournit l’orchestration, la validation étape par étape, et la persistance d’état.

Le pattern est plus déclaratif et s’intègre avec les Forms standard. Pour les apps SaaS qui ont des onboarding multi-pages, c’est un sérieux gain de DX.

⚠️ Quelques précautions

  • PHP 8.4 mini : vérifie les drivers (Doctrine, Redis, Memcached) et les extensions C. Quasi tout suit, mais une CI verte vaut mieux qu’un déploiement chaotique.
  • UUID v7 : si tu reposes sur le hasard d’un UUID v4 pour quoi que ce soit (split A/B, sharding par bucket), réfléchis avant de basculer.
  • XML déprécié : pas urgent à migrer, mais à planifier avant 9.0.
  • Bundles tiers : la majorité supporte 8.0 depuis novembre, mais reste prudent sur des bundles peu maintenus. Une PR composer.json constraints suffira souvent.
  • Caching HTTP client : à activer requête par requête au début, pas globalement. Tu veux éviter de cacher une réponse d’API d’auth.

🎉 Conclusion

Symfony 8.0 est une majeure tranquille, mais structurante. Le palier PHP 8.4 ouvre la voie à du code plus moderne, UUID v7 corrige un défaut de design qu’on avait fini par accepter, et la dépréciation XML clarifie la stack de config. Les nouveaux composants (cache HTTP RFC 9111, multi-step forms, signing Messenger) répondent à des besoins concrets sans inventer d’abstraction inutile.

Si tu démarres un projet en 2026, prends directement Symfony 8.1. Si tu migres depuis 7.x, vise la 8.0 pour récupérer le palier PHP puis enchaîne sur 8.1 pour le polish DI / HttpClient. La trajectoire est claire et reste prévisible.

🔗 Liens utiles