Legacy-Code in eine Symfony-Anwendung integrieren

Sie müssen Legacy in Symfony integrieren, ohne alles neu zu schreiben? So kapseln Sie funktionierenden Altcode sauber, ohne jahrelang bewährte Fachlogik wegzuwerfen.

Sie stehen vor einer PHP-Anwendung, die seit Jahren zuverlässig läuft, und sollen sie in eine moderne Symfony-Struktur überführen. Der erste Reflex vieler Teams: alles neu bauen. Aus meiner Erfahrung ist das fast immer die teuerste und riskanteste Option. Ein System, das über Jahre in Produktion überlebt hat, ist kein Müll – es ist der Beweis, dass die Fachlogik funktioniert. Das eigentliche Problem sitzt selten in der Berechnung eines Rabatts oder einer Provision, sondern im Code drumherum: globale Variablen, direktes SQL im Controller, Ausgabe und Logik im selben File.

Wenn Sie Legacy in Symfony integrieren wollen, geht es deshalb nicht darum, den Kern wegzuwerfen. Es geht darum, ihn aus seinem alten Umfeld zu befreien und in eine saubere Umgebung zu stellen, in der er weiterlebt.

Warum Neuentwicklung fast immer die falsche Antwort ist

Eine Neuentwicklung bedeutet, dass Sie jahrelang gewachsenes Wissen erneut aufbauen. In der Praxis steckt in altem Code eine Menge undokumentiertes Fachwissen: Sonderfälle für bestimmte Kunden, steuerliche Rundungsregeln, Ausnahmen, die irgendwann aus gutem Grund eingebaut wurden. Diese Details stehen nirgends in einem Ticket. Sie stehen nur im Code.

Schreiben Sie das System neu, riskieren Sie, genau diese Fälle zu verlieren – und Sie merken es oft erst Monate später, wenn ein Kunde sich über eine falsche Rechnung beschwert. Die Integration bestehender Logik in Symfony ist deshalb in der Regel schneller, billiger und deutlich risikoärmer. Sie behalten das bewährte Verhalten und modernisieren nur die Hülle.

Der erste Schritt: Symfony als Rahmen, Altcode als Gast

Der pragmatischste Einstieg ist, Symfony vor die bestehende Anwendung zu setzen, ohne sofort etwas zu ersetzen. Sie richten eine frische Symfony-Anwendung ein und lassen den alten Code zunächst als eingebundene Bibliothek laufen. Das nennt sich oft Strangler-Fig-Pattern: Neue Anfragen laufen durch Symfony, altes Verhalten wird schrittweise abgelöst, statt in einem Big Bang.

Konkret heißt das: Sie legen den Legacy-Code als eigenes Verzeichnis ins Projekt und machen ihn über den Autoloader erreichbar. Hat der Altcode keine PSR-4-Struktur, hilft ein Classmap-Eintrag in der composer.json:

"autoload": { "classmap": ["legacy/"] }

Danach führen Sie composer dump-autoload aus. Ab hier kann Symfony die alten Klassen laden, ohne dass Sie eine einzige Zeile Fachlogik anfassen mussten.

Legacy in Symfony integrieren: Kapseln statt umschreiben

Der entscheidende Trick ist die Kapselung. Sie rufen alten Code nicht wild aus Ihren neuen Controllern heraus auf, sondern verstecken ihn hinter einem sauberen Symfony-Service. So bleibt der Rest Ihrer Anwendung frei von Legacy-Details.

Ein Beispiel: Ihre alte Anwendung berechnet Frachtkosten über eine Funktion berechne_fracht($gewicht, $zone), die irgendwo in einer prozeduralen Datei liegt. Statt diese Funktion überall aufzurufen, bauen Sie einen Adapter:

final class FrachtRechner { public function berechne(Sendung $s): Money { return Money::euro(berechne_fracht($s->gewicht(), $s->zone())); } }

Diesen Service registrieren Sie im Container und injizieren ihn per Dependency Injection. Der große Gewinn: Ihre neue Codebasis kennt nur das saubere Interface. Der alte Code sitzt an genau einer Stelle. Wenn Sie ihn später ersetzen, ändern Sie nur das Innere des Adapters – der Rest der Anwendung merkt nichts davon.

Was tun mit globalem State und direkten Datenbankzugriffen?

Alte Anwendungen greifen oft über eigene, globale Datenbankverbindungen zu, häufig noch mit der veralteten mysql_*-Schnittstelle oder handgeschriebenen Queries. Erzwingen Sie hier keinen Sofortumbau auf Doctrine. Lassen Sie die alte Verbindung zunächst weiterlaufen, aber konfigurieren Sie sie über Symfony-Parameter statt über hartkodierte Werte. So haben Sie Zugangsdaten und Umgebungen an einer Stelle.

Kritisch ist die Sicherheit: Prüfen Sie beim Herausziehen jeden Query auf SQL-Injection. Alter Code, der Nutzereingaben direkt in Strings konkateniert, ist die häufigste Schwachstelle, die mir begegnet. Wenn Sie ohnehin die Aufrufe kapseln, ist das der ideale Moment, Prepared Statements einzuziehen.

Sessions, Authentifizierung und die Übergabe zwischen alt und neu

Ein oft unterschätzter Punkt ist die gemeinsame Session. Wenn Symfony und Altcode parallel laufen, dürfen sie sich nicht gegenseitig die Session zerschießen. Sorgen Sie dafür, dass beide denselben Session-Namen und dieselbe Speicherung nutzen. In Symfony konfigurieren Sie das über framework.session; im Altcode müssen Sie sicherstellen, dass er nicht sein eigenes session_start() mit abweichenden Einstellungen aufruft.

Für die Authentifizierung empfiehlt es sich, mittelfristig die Symfony-Security-Komponente zum führenden System zu machen. Bis dahin können Sie einen kleinen Brückenmechanismus bauen, der den eingeloggten Nutzer aus der alten Session liest und Symfony bekannt macht. Wichtig: Behandeln Sie diese Brücke als Übergang, nicht als Dauerlösung.

Schrittweise ablösen, nicht alles auf einmal

Sobald der Altcode sicher eingebettet ist, lösen Sie ihn Stück für Stück ab. Ein bewährtes Vorgehen:

  1. Kapseln Sie einen Bereich hinter einem Service-Interface.
  2. Schreiben Sie Charakterisierungstests, die das aktuelle Verhalten festhalten – auch die merkwürdigen Sonderfälle.
  3. Ersetzen Sie die Implementierung hinter dem Interface durch sauberen Symfony-Code.
  4. Prüfen Sie gegen die Tests, dass sich das Verhalten nicht geändert hat.

Diese Tests sind Ihr Sicherheitsnetz. Sie erlauben es, mutig umzubauen, ohne das Risiko, unbemerkt Fachlogik zu verändern. Gerade weil altes Verhalten selten dokumentiert ist, sind Tests hier wertvoller als jedes Refactoring-Werkzeug.

Ein ehrlicher Praxis-Tipp zum Schluss

Fangen Sie klein an. Nehmen Sie einen einzigen, klar abgegrenzten Anwendungsfall – etwa eine Berechnung oder einen Report – und integrieren Sie nur diesen sauber in Symfony. Sie lernen dabei die Eigenheiten des Altsystems kennen, ohne das ganze Projekt zu riskieren. Widerstehen Sie der Versuchung, alles gleichzeitig anzufassen: Die schrittweise Ablösung ist unbequemer, aber sie ist der einzige Weg, der bewährte Fachlogik nicht opfert.

Wenn Sie bei genau solchen Migrationen einen erfahrenen Blick von außen brauchen, unterstützt LegacyWerk Sie dabei, Altsysteme risikoarm in Symfony zu überführen.

Legacy schrittweise in Symfony integrieren Legacy-Code bewaehrte Fachlogik Adapter / Service Kapselung, DI Symfony neue Huelle Ablauf 1 Kapseln 2 Tests schreiben 3 Ersetzen 4 Pruefen

Vollmodernisierung: Festpreis nach Befund, 2–6 Monate

Kompatibilität plus Struktur: Tests, saubere Schichten, Datenbank-Integrität, CI/CD – damit Ihr Team wieder bauen kann. Sie schildern mir Ihr System in drei kurzen Schritten, ich antworte mit einer ehrlichen Einschätzung und einem Festpreis.

Vollmodernisierung anfragen