Réusinage de code legacy PHP : de A à Z
Travailler avec du code obsolète (legacy) est une étape inévitable dans la vie de tout développeur PHP. Tôt ou tard, vous rencontrerez un projet écrit en PHP 5.6 (voire 4), sans autoloading, utilisant des variables globales, et où la logique métier est mélangée avec du HTML. Le réusinage d'un tel code n'est pas un simple "nettoyage", mais un processus stratégique qui peut sauver un projet de la dette technique et le rendre maintenable.
Dans cet article, nous allons voir comment aborder le réusinage de code legacy PHP de manière systématique, sans casser les fonctionnalités existantes, et transformer un "bourbier" en un code moderne et testable.
1. Diagnostic et évaluation : par où commencer ?
Avant de modifier le code, il faut comprendre à quoi vous avez affaire. Commencez par un audit du projet.
Étape 1. Identifiez les "points douloureux"
- Dépendances : Des bibliothèques obsolètes sont-elles utilisées ? Par exemple, les fonctions
mysql_*au lieu de PDO ou MySQLi. - Architecture : Y a-t-il une quelconque structure (MVC) ? Ou tout le code est-il dans un seul fichier
index.php? - Tests : Existe-t-il des tests automatisés ? Si non, c'est votre priorité numéro un.
Étape 2. Outils d'analyse
Utilisez des analyseurs statiques pour identifier rapidement les zones problématiques :
- PHPStan / Psalm : Trouveront les erreurs de type et les incohérences de signature.
- Rector : Mettra automatiquement à jour la syntaxe vers une nouvelle version de PHP.
- PhpMetrics : Affichera la complexité cyclomatique et la cohésion du code.
Exemple d'exécution de Rector pour une mise à jour de PHP 7.4 vers 8.0 :
vendor/bin/rector process src/ --set php802. Stratégie "Chirurgie sans douleur" : plan étape par étape
Le réusinage de code legacy n'est pas un "big bang". C'est une série de petites étapes sûres. Utilisez la technique du "Strangler Fig" (figuier étrangleur) — remplacez progressivement les anciens modules par des nouveaux, sans tout réécrire d'un coup.
Étape 1. Couvrez le code de tests
Sans tests, le réusinage est une roulette russe. Commencez par des tests de caractérisation (characterization tests) :
class LegacyCalculatorTest extends TestCase { public function testOldCalculation(): void { // On exécute l'ancien code et on enregistre le résultat $result = legacy_calculation(10, 5); $this->assertEquals(15, $result); }}Cela créera un "filet de sécurité" avant les modifications.
Étape 2. Isolez la logique "sale"
Si le code utilise des variables globales ($GLOBALS), extrayez-les en paramètres de fonction :
// Avant (dépendance globale)function processOrder() { global $db; $result = $db->query("SELECT * FROM orders");}
// Après (injection de dépendance)function processOrder(PDO $db) { $result = $db->query("SELECT * FROM orders");}Étape 3. Remplacez les fonctions obsolètes
Par exemple, remplacement de mysql_* par PDO :
// Ancien code$link = mysql_connect('localhost', 'user', 'pass');mysql_select_db('test', $link);$result = mysql_query("SELECT * FROM users", $link);
// Nouveau code (PDO)$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');$stmt = $pdo->query("SELECT * FROM users");$result = $stmt->fetchAll(PDO::FETCH_ASSOC);3. Problèmes typiques du PHP legacy et leurs solutions
Problème 1 : "Code spaghetti" (mélange de logique et de présentation)
Solution : Séparez le code en couches. Extrayez la logique métier dans des classes dédiées, et le HTML dans des templates (par exemple, avec Twig).
// Mauvais : logique et HTML dans le même fichierif ($user->isAdmin()) { echo "<h1>Bonjour, admin !</h1>";} else { echo "<h1>Bonjour, utilisateur !</h1>";}
// Bon : contrôleur + template//