Introduction : pourquoi le refactoring du code legacy n'est pas un luxe, mais une nécessité
Chaque développeur PHP est tôt ou tard confronté à du code legacy. Cela peut être un projet écrit il y a 10 ans en PHP 5.3, ou une application qui « fonctionne juste », mais qui provoque des douleurs à chaque modification. Le refactoring de ce code n'est pas simplement un « coup de peigne » sur le style, mais un processus critique qui améliore la maintenabilité, les performances et la sécurité de l'application.
Dans cet article, nous allons détailler des approches pratiques pour le refactoring de code PHP legacy, en utilisant les fonctionnalités modernes du langage (PHP 7.4–8.3) et des patterns éprouvés. Vous apprendrez comment apporter des modifications en toute sécurité, sans casser le système en fonctionnement.
1. Évaluation et documentation de l'état actuel
La première et la plus importante étape est de comprendre à quoi vous avez affaire. N'essayez pas de refactoriser à l'aveugle.
1.1. Créez une carte des dépendances
Utilisez des outils comme PhpMetrics ou Deptrac pour visualiser les liens entre les classes. Cela aidera à identifier les « objets divins » (god objects) et les dépendances cycliques.
// Exemple d'une classe "divine" typique dans du code legacyclass UserManager { public function save($data) { // 200 lignes de code : validation, envoi d'email, logging, travail avec la BD } public function sendNewsletter() { // Encore 150 lignes } public function generateReport() { // Et encore 100 lignes }}1.2. Écrivez des tests de caractérisation
Avant de modifier le code, assurez-vous que le comportement actuel est documenté par des tests. Utilisez l'approche « Golden Master » (snapshot testing) :
// Test qui fige le comportement actuelpublic function testLegacyCalculation(): void{ $calculator = new OldCalculator(); $result = $calculator->compute(10, 20); // S'il n'y a pas de spécification, on sauvegarde simplement le résultat $this->assertSame(30, $result);}Conseil : Si le projet est totalement sans tests, commencez par des tests d'intégration sur les opérations métier critiques. Utilisez PHPUnit avec vfsStream pour isoler le système de fichiers.
2. Amélioration progressive : des fonctions globales à la POO
Une grande partie du code PHP legacy est constituée de fonctions globales et de style procédural. La migration progressive vers la POO est une étape clé du refactoring.
2.1. Encapsulation des fonctions globales
Remplacez les fonctions globales par des méthodes statiques de classe, puis par des services à part entière.
// Avant : fonction globalefunction send_email($to, $subject, $message) { mail($to, $subject, $message);}
// Après : classe de serviceclass MailService { public function __construct( private MailerInterface $mailer ) {} public function send(string $to, string $subject, string $message): bool { return $this->mailer->send($to, $subject, $message); }}2.2. Se débarrasser des variables globales
Les variables globales ($GLOBALS, $_SESSION directement) sont la principale source de bugs. Utilisez le pattern Registry ou l'injection de dépendances (DI).
// Mauvais : travail direct avec les variables globalesfunction getCurrentUser() { global $db; $id = $_SESSION['user_id']; return $db->query("SELECT * FROM users WHERE id = $id");}
// Bon : injection de dépendances expliciteclass UserProvider { public function __construct( private PDO $db, private SessionInterface $session ) {} public function getCurrentUser(): ?User { $id = $this->session->get('user_id'); return $this->db->query('SELECT * FROM users WHERE id = ?', [$id]); }}3. Remplacement sécurisé des constructions obsolètes
PHP évolue, et de nombreuses anciennes constructions sont devenues non sécurisées et