Aller au contenu principal
Retour au blog

De Symfony 7.4 LTS à la branche 8.x : éliminer les dépréciations proprement

Symfony 7.4 et 8.0 partagent le même code, moins les dépréciations. Méthode outillée pour migrer sans mauvaise surprise : détection, audit, Rector.

Flavien Métivier · 9 min de lecture
Sommaire · 7 parties

Fin novembre 2025, Symfony a livré 7.4 et 8.0 le même jour, avec exactement le même jeu de fonctionnalités. Presque un an plus tard, alors que 8.1 est la version stable de référence et que 8.2 pointe pour novembre 2026, une partie non négligeable des projets que nous accompagnons tourne encore sur des branches 6.4 ou 7.x antérieures, avec un mur de dépréciations jamais traité. Le problème n'est pas technique — c'est une question de méthode. Sauter directement sur 8.0 depuis une 7.2 par exemple, c'est se condamner à corriger des dizaines de trigger_deprecation() en même temps qu'on absorbe des breaking changes réels. Il existe une route plus sûre, documentée par l'équipe cœur de Symfony elle-même, et c'est celle que nous suivons systématiquement dans nos accompagnements de montée de version.

7.4 et 8.0 : la même release, moins les couches de dépréciation

Le modèle de double sortie n'est pas nouveau chez Symfony, mais il change la donne pour la stratégie de migration. Symfony 8.0 est littéralement Symfony 7.4 débarrassé de toutes les dépréciations accumulées depuis la 7.0. Aucune fonctionnalité n'existe dans l'une sans exister dans l'autre — la 8.0 se contente de retirer le code de compatibilité ascendante et les couches trigger_deprecation() qui permettaient aux applications 7.x de continuer à fonctionner avec des API historiques. Pour une équipe qui migre, cette symétrie est une aubaine : on peut valider son code sur 7.4 en conditions quasi identiques à 8.0, dépréciation par dépréciation, avant de faire le saut. J'avais détaillé les nouveautés et le calendrier de support de cette LTS dans un article dédié à Symfony 7.4 LTS — la partie qui nous intéresse ici, c'est ce qu'on fait une fois dessus.

  • Symfony 7.4 (LTS) — bugfixes jusqu'en novembre 2028, sécurité jusqu'en novembre 2029. C'est la branche de repli pour les projets qui ne veulent pas suivre le rythme semestriel des versions régulières.
  • Symfony 8.0 (régulière) — support limité à huit mois, terminé depuis juillet 2026. Ne pas s'y arrêter : c'est un tremplin vers 8.1, pas une destination.
  • Symfony 8.1 — sortie le 29 mai 2026, version stable actuelle au moment où j'écris ces lignes, avec un focus marqué sur les applications HTTP-less (workers, CLI, consumers asynchrones).
  • Symfony 8.2 — attendue pour novembre 2026, poursuit le cycle semestriel classique de Symfony (releases en mai et novembre).

La stratégie recommandée : d'abord 7.4, jamais 8.0 en direct

L'équipe Symfony est explicite sur ce point dans son article de préparation à la double sortie : ne migrez pas directement vers 8.0 depuis une version antérieure. La séquence qui fonctionne, et que nous appliquons projet après projet, tient en trois temps. D'abord, on monte sur 7.4 — que le projet vienne de 6.4 LTS ou d'une 7.x intermédiaire, la mécanique de montée mineure/majeure ne change pas : mise à jour Composer, recettes Flex, lecture des fichiers UPGRADE-X.Y.md. Ensuite, et c'est l'étape qui prend le plus de temps réel, on nettoie toutes les dépréciations pendant que l'application tourne encore sur 7.4 — donc sans rien casser en production. Enfin seulement, on saute sur 8.0, puis on continue le rythme semestriel vers 8.1 et 8.2 sans jamais laisser retomber la dette. Pour le détail de la checklist de démarrage d'une migration Symfony, j'avais posé le cadre général dans cet article sur par où commencer une migration Symfony — ce qui suit se concentre spécifiquement sur l'étape de nettoyage des dépréciations, qui est de loin la plus sous-estimée.

Cette méthode a un corollaire important pour la planification : rester bloqué sur 7.4 LTS n'est pas un problème en soi tant que le support couvre le projet, mais chaque cycle de dépréciations non traité qu'on laisse s'accumuler jusqu'à la prochaine LTS (8.4, prévue pour novembre 2027) reproduit exactement le même mur qu'on essaie d'éviter aujourd'hui. Traiter les dépréciations au fil de l'eau, à chaque montée mineure, coûte une fraction du temps qu'un rattrapage massif tous les trois ans.

Détecter les dépréciations avant qu'elles ne deviennent des breaking changes

Trois outils suffisent à obtenir une vue complète des dépréciations d'un projet, et ils sont complémentaires plutôt que redondants. Le premier, et le plus rapide à mettre en place, c'est le flag natif de PHPUnit :

bash
# Affiche le détail des dépréciations à la fin de la suite de tests
php bin/phpunit --display-deprecations

# Sortie typique
OK, but there were issues!
Tests: 342, Assertions: 891, Deprecations: 14.

Remaining deprecation notices (9)

9x: Since symfony/security-core 7.3: Not setting the "$secret" argument
is deprecated, it will be required in 8.0.
  9x in ProductVoterTest::testVoteOnOwner from App\Tests\Security

Remaining direct deprecation notices (5)

5x: Since symfony/http-kernel 7.2: Using the "kernel.event_listener"
tag without the "event" attribute is deprecated.
  3x in EventSubscriberTest
  2x in KernelTestCase

La distinction entre dépréciations directes (dans le code applicatif, à corriger toi-même) et indirectes (déclenchées par du code de vendor/, hors de ton contrôle immédiat) est ce qui rend cette sortie exploitable en priorité plutôt qu'en volume brut. Le second outil, complémentaire pour tout ce qui n'est pas couvert par une suite de tests automatisés, c'est le panneau Deprecations du profiler Symfony en environnement dev — chaque requête HTTP y remonte les dépréciations qu'elle a déclenchées, avec la stack trace complète. C'est particulièrement utile pour les parcours qui ne sont pas encore testés, ce qui, soyons honnêtes, arrive sur tous les projets un peu anciens. Le troisième outil n'est pas un outil de détection mais l'infrastructure qui rend les deux premiers possibles : symfony/deprecation-contracts, le paquet qui expose la fonction trigger_deprecation() utilisée par le framework lui-même et par les bundles tiers qui la respectent. Comprendre son fonctionnement aide à distinguer un vrai signal (une API va disparaître) d'un faux positif lié à une configuration error_reporting trop permissive côté PHP.

composer audit : sécuriser la migration, pas seulement la moderniser

Une migration majeure est le moment idéal pour auditer les dépendances de sécurité, pour une raison simple : tu vas déjà toucher au composer.lock sur l'ensemble du projet, autant en profiter pour ne pas réintroduire de vulnérabilités connues au passage. SymfonyCasts consacre d'ailleurs une leçon entière de son cours Upgrading to Symfony 8 à cette étape — Composer Audit and Security Updates — dans le contexte d'une revue de sécurité approfondie qui a mis au jour plusieurs vulnérabilités dans l'écosystème PHP courant 2026, relayée notamment dans la newsletter hebdomadaire A Week of Symfony. La commande elle-même est native à Composer depuis la 2.4 et ne nécessite aucun plugin :

Migration Symfony en vue ?

Bear Upgrade migre votre codebase 2,5× à 4,5× moins cher qu'une ESN, selon sa maturité.

Estimer ma migration →
bash
# Audit des CVE connues sur les dépendances installées (base Packagist / FriendsOfPHP)
composer audit

# Format exploitable en CI, échoue si une CVE est trouvée
composer audit --format=json --no-dev

# Combiné à la montée de version : on force la mise à jour du lock
# avant l'audit pour ne pas auditer un état obsolète
composer update "symfony/*" --with-all-dependencies
composer audit

L'ordre compte : auditer un composer.lock qui n'a pas encore reçu la mise à jour vers 7.4 donne une photo de l'existant, pas de la cible. On exécute donc composer audit une première fois en état des lieux, puis une seconde fois une fois les paquets Symfony et leurs dépendances transitives mis à jour, pour vérifier qu'aucune régression de sécurité n'a été introduite par la montée de version elle-même. Sur les projets où la CI est configurée strictement, cette seconde commande doit faire échouer le pipeline sans continue-on-error — une CVE HIGH ou CRITICAL découverte pendant une migration n'est jamais un détail à traiter plus tard.

Automatiser avec Rector : les dépréciations mécaniques ne se corrigent pas à la main

Une grande partie des dépréciations relevées par PHPUnit sont mécaniques : un argument renommé, une méthode dépréciée au profit d'une autre au comportement identique, un attribut PHP qui remplace une annotation. Les corriger à la main fichier par fichier est à la fois lent et source d'erreurs de copier-coller. C'est exactement le terrain de jeu de Rector, dont j'avais détaillé la mécanique générale et les cas d'usage dans l'article sur l'automatisation du refactoring PHP avec Rector. Le paquet rector/rector embarque nativement les règles de migration Symfony, activables sans configuration additionnelle :

php
<?php
// rector.php — configuration pour la remontée 7.x vers 7.4/8.0
declare(strict_types=1);

use Rector\Config\RectorConfig;

return RectorConfig::configure()
    ->withPaths([
        __DIR__ . '/src',
        __DIR__ . '/tests',
    ])
    // Active les règles de qualité de code Symfony (renommages,
    // signatures de méthodes, attributs) déjà maintenues par le paquet
    ->withPreparedSets(
        symfonyCodeQuality: true,
        deadCode: true,
    )
    // Détecte automatiquement les paquets Symfony/Doctrine installés
    // et applique les règles correspondant aux versions du composer.lock
    ->withComposerBased(
        symfony: true,
        doctrine: true,
    )
    ->withPhpSets(php85: true);

L'exécution en mode --dry-run d'abord, puis en écriture réelle avec relecture du diff avant commit, reste la méthode la plus sûre — Rector modifie du code source directement, il ne se contente pas de signaler. Sur un projet de taille moyenne, ce passage automatisé traite couramment 60 à 80 % des dépréciations directes remontées par --display-deprecations, ce qui laisse l'équipe se concentrer sur les 20 à 40 % qui demandent un vrai jugement métier — typiquement des changements de comportement plutôt que de simple signature.

Les dépréciations indirectes : quand le problème vient d'un bundle tiers

C'est le cas qui bloque le plus souvent une migration en pratique. Une dépréciation indirecte signifie que le code qui l'émet est dans vendor/, pas dans src/ — impossible de la corriger directement sans forker le paquet. Trois options, dans l'ordre de préférence : vérifier si une version plus récente du bundle a déjà corrigé l'appel déprécié (souvent le cas, une simple mise à jour Composer suffit) ; si le mainteneur n'a pas encore publié de fix, ouvrir une issue en pointant la ligne exacte remontée par la stack trace du profiler — c'est un service rendu à toute la communauté qui utilise ce bundle ; en dernier recours, si le projet est bloqué par une dépendance non maintenue, l'ajout d'un patch Composer via cweagans/composer-patches le temps de trouver une alternative. Ce qu'il ne faut jamais faire, c'est ignorer une dépréciation indirecte sous prétexte qu'elle n'est "pas de notre faute" — au moment du saut vers 8.0, l'API dépréciée aura disparu, et le bundle cassera en production si personne ne l'a mis à jour entre-temps.

Le workflow complet, étape par étape

  • 1. Photographier l'existant — composer audit et php bin/phpunit --display-deprecations sur la version actuelle, avant tout changement de dépendance.
  • 2. Monter sur 7.4 — mise à jour Composer (via extra.symfony.require si Flex est en place), recettes à jour, lecture des UPGRADE-7.4.md pertinents.
  • 3. Nettoyer les dépréciations directes — passe Rector en --dry-run puis en écriture, relecture du diff, puis correction manuelle du reste.
  • 4. Traiter les dépréciations indirectes — mise à jour des bundles tiers, signalement upstream pour ce qui reste bloqué.
  • 5. Revalider à zéro dépréciation — --display-deprecations doit remonter Deprecations: 0 avant de passer à l'étape suivante, sans quoi le saut vers 8.0 casse en silence.
  • 6. Sauter sur 8.0, puis enchaîner 8.1, 8.2 au rythme semestriel, en répétant les étapes 1 et 3 à chaque montée mineure plutôt que d'attendre la prochaine LTS.

Ce qui distingue une migration bien menée d'une migration qui traîne en longueur, ce n'est jamais la complexité technique des breaking changes eux-mêmes — Symfony documente chacun d'eux avec précision. C'est la discipline à suivre la séquence dans l'ordre, sans raccourci, et à ne pas laisser les dépréciations s'accumuler entre deux versions mineures. Sur les projets où cette dette est déjà installée depuis plusieurs cycles, ou quand l'équipe interne n'a simplement pas le temps de dérouler cette checklist en parallèle du reste de la roadmap, c'est précisément le terrain sur lequel intervient notre accompagnement Bear Upgrade : on prend en charge la montée de version de bout en bout — audit des dépréciations, automatisation Rector, revue de sécurité Composer — pour livrer un projet à jour sans interrompre le développement de nouvelles fonctionnalités pendant des semaines.

Cet article vous a été utile ? Partagez-le.

Portrait de Flavien Métivier, fondateur de The Bearded Bear : barbe longue, lunettes, sur fond sombre

Écrit par

Flavien Métivier

Expert PHP/Symfony indépendant depuis 2014, ancien CTO de Kartable et d'Extrabat. Plus de 80 projets menés, de l'audit à la migration.

Mon parcours

À lire ensuite

Migration Symfony en vue ?

Bear Upgrade migre votre codebase 2,5× à 4,5× moins cher qu'une ESN, selon sa maturité.

Newsletter Bear Bytes

Veille Claude Code, Symfony et PHP, retours d'expérience terrain et conseils techniques, directement dans votre boîte mail.