Einleitung: Warum Refactoring von Legacy-Code kein Luxus, sondern eine Notwendigkeit ist
Jeder PHP-Entwickler stößt früher oder später auf Legacy-Code. Das kann ein Projekt sein, das vor 10 Jahren mit PHP 5.3 geschrieben wurde, oder eine Anwendung, die „einfach funktioniert“, aber bei jeder Änderung Schmerzen bereitet. Das Refactoring solchen Codes ist nicht nur ein „Kämmen“ des Stils, sondern ein kritisch wichtiger Prozess, der die Wartbarkeit, Leistung und Sicherheit der Anwendung verbessert.
In diesem Artikel werden wir praktische Ansätze zum Refactoring von Legacy-PHP-Code untersuchen, indem wir moderne Sprachfunktionen (PHP 7.4–8.3) und bewährte Patterns verwenden. Sie erfahren, wie Sie sicher Änderungen vornehmen können, ohne das funktionierende System zu beschädigen.
1. Bewertung und Dokumentation des aktuellen Zustands
Der erste und wichtigste Schritt ist zu verstehen, womit Sie es zu tun haben. Versuchen Sie nicht, blind zu refactoren.
1.1. Erstellen Sie eine Abhängigkeitskarte
Verwenden Sie Tools wie PhpMetrics oder Deptrac, um die Verbindungen zwischen Klassen zu visualisieren. Dies hilft dabei, „God Objects“ und zyklische Abhängigkeiten zu identifizieren.
// Beispiel einer typischen "God"-Klasse in Legacy-Codeclass UserManager { public function save($data) { // 200 Zeilen Code: Validierung, E-Mail-Versand, Logging, Datenbankarbeit } public function sendNewsletter() { // Nochmal 150 Zeilen } public function generateReport() { // Und nochmal 100 Zeilen }}1.2. Schreiben Sie charakteristische Tests
Bevor Sie Code ändern, stellen Sie sicher, dass das aktuelle Verhalten durch Tests dokumentiert ist. Verwenden Sie den „Golden Master“-Ansatz (Snapshot Testing):
// Test, der das aktuelle Verhalten festhältpublic function testLegacyCalculation(): void{ $calculator = new OldCalculator(); $result = $calculator->compute(10, 20); // Wenn es keine Spezifikation gibt, speichern wir einfach das Ergebnis $this->assertSame(30, $result);}Tipp: Wenn das Projekt ganz ohne Tests ist, beginnen Sie mit Integrationstests für kritische Geschäftsoperationen. Verwenden Sie PHPUnit mit vfsStream zur Isolierung des Dateisystems.
2. Schrittweise Verbesserung: Von globalen Funktionen zu OOP
Ein Großteil des Legacy-PHP-Codes besteht aus globalen Funktionen und prozeduralem Stil. Die schrittweise Migration zu OOP ist ein Schlüsselschritt beim Refactoring.
2.1. Kapselung globaler Funktionen
Ersetzen Sie globale Funktionen durch statische Methoden einer Klasse, dann durch vollwertige Services.
// Vorher: globale Funktionfunction send_email($to, $subject, $message) { mail($to, $subject, $message);}
// Nachher: Service-Klasseclass 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. Beseitigung globaler Variablen
Globale Variablen ($GLOBALS, $_SESSION direkt) sind die Hauptquelle für Bugs. Verwenden Sie das Registry-Pattern oder Dependency Injection (DI).
// Schlecht: direkte Arbeit mit globalen Variablenfunction getCurrentUser() { global $db; $id = $_SESSION['user_id']; return $db->query(\"SELECT * FROM users WHERE id = $id\");}
// Gut: explizite Dependency Injectionclass 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. Sicherer Austausch veralteter Konstrukte
PHP entwickelt sich weiter, und viele alte Konstrukte sind unsicher geworden und