Migration d’une Application legacy PHP 7 vers PHP 8 et Symfony récent : Feuille de route et bonnes pratiques

La migration d’une application legacy PHP 7 vers PHP 8 et une version récente de Symfony est un projet stratégique pour garantir sécurité, performance et maintenabilité. Voici une feuille de route conseillée, les pièges courants et les bonnes pratiques, assortis de sources crédibles.

Pourquoi migrer ?

  • Sécurité : depuis novembre 2022, PHP 7 n’est plus maintenu, les correctifs de sécurité ne sont plus assurés.
  • Performance & nouvelles fonctionnalités : PHP 8 apporte typage plus strict, attributs, promotion de propriétés, meilleures performances.
  • Écosystème Symfony : les nouvelles versions apportent des fonctions modernes, retirent les API dépréciées, améliorent la compatibilité avec les librairies actuelles.

Feuille de route

Voici les étapes recommandées pour une migration progressive et maîtrisée :

ÉtapeActions recommandées
1. Audit & Diagnostic Initial– Lister l’architecture, dépendances, bundles, extensions PHP utilisées.
– Repérer les usages de fonctions ou APIs dépréciées.
– Vérifier versions minima de PHP / Symfony requises par vos dépendances.
2. Mise à niveau intermédiaire– Si le gap est important, migrer par paliers : par exemple PHP 7.4, Symfony 3 → 4 → 5 ou 6.
– Mettre à jour les versions mineures de Symfony pour obtenir les messages de dépréciation avant de passer à une grande version majeure.
– Dans composer.json, adapter les contraintes de version pour Symfony et PHP.
3. Utilisation de Rector pour automatiser la refactorisation– Rector permet d’appliquer des règles de migration (sets) pour PHP 8 ou versions Symfony spécifiques.
– On peut configurer Rector pour ne traiter que certaines parties du code, faire des passes progressives.
– Toujours coupler Rector avec une suite de tests robuste.
4. Adapter le code– Remplacer les annotations par des attributs si nécessaire.
– Introduire typage stricte, types de retour, types de paramètres, propriétés typées.
– Éliminer le code mort, les dépendances obsolètes.
– Revues de code et tests unitaires/fonctionnels à chaque étape.
5. Tests & validation– Couverture de tests importante avant migration majeure.
– Automatiser via CI/CD.
– Validation en environnement de staging, test de performance, de montée en charge, de compatibilité.
6. Déploiement & suivi post-migration– Plan de rollback si problème.
– Monitoring renforcé : logs, outils de performance, alertes.
– Surveiller les dépréciations supprimées après la migration pour corriger rapidement.

Bonnes pratiques et outils utiles

  • Lire la documentation officielle de Symfony sur les mises à jour majeures. Exemple : Upgrading a Major Version — Symfony Docs
  • Utiliser Rector pour automatiser la mise à jour de certaines parties du code. Source : « How to Confidently Update Legacy Code in Symfony », Ekino France. medium.com
  • Vérifier les dépréciations à l’avance : avant de monter en version majeure, être “dépréciation-free” dans la version actuelle. Symfony offre des outils qui affichent les usages dépréciés. insight.symfony.com
  • Adapter les dépendances externes : certains bundles ou librairies ne sont pas maintenus ou pas compatibles avec PHP 8 ou les versions récentes de Symfony. reddit.com

Exemple de Configuration Rector de Base

Voici un exemple de configuration basique de rector.php pour une migration vers PHP 8.x et nettoyage de code :

<?php
declare(strict_types=1);
use Rector\Config\RectorConfig;
use Rector\Core\ValueObject\Set\SetList;
return static function (RectorConfig $config): void {
// Chemins de votre code à refactorer
$config->paths([ __DIR__ . '/src', __DIR__ . '/config', __DIR__ . '/tests', ]);
// Activer les sets PHP 8.0+ selon vos objectifs
$config->sets([ SetList::PHP_80, SetList::CODE_QUALITY, SetList::DEAD_CODE, ]);
// Vous pouvez aussi ajouter des règles personnalisées
// $config->rule(App\Rector\SomeCustomRector::class);
};

Risques à Anticiper

  • Incompatibilités silencieuses : des différences de comportement de PHP ou de Symfony non détectées par les tests.
  • Dépendances non maintenues qui bloquent la montée de version.
  • Coûts cachés : temps passé sur refactorisation, résolution de bugs post-migration.
  • Régression de performances si le code n’est pas optimisé après mise à jour.