Von Symfony 2/3 zu Symfony 7: Eine schrittweise Migrationsstrategie

Sandor Farkas
Gründer & Lead Developer
Experte für Softwareentwicklung und Legacy-Code-Optimierung
LinkedInEine Symfony-2- oder Symfony-3-Anwendung, die heute in Produktion läuft, hat typischerweise Jahre voller Featureerweiterungen, Teamwechsel und angesammelter Workarounds hinter sich. Eine direkte Migration von Symfony 2 auf 7 ist keine Migration - es ist eine Neuentwicklung mit vertrauter Verzeichnisstruktur. Die Lücke zwischen diesen Versionen umfasst fünf Major-Releases, vier PHP-Mindestanforderungen, eine komplett ersetzte Security-Schicht, die Einführung von Symfony Flex und die Entfernung dutzender APIs, auf die dein Codebase fast sicher angewiesen ist.
Teams, die diese Art von Legacy-Symfony-Upgrade erfolgreich durchführen, tun dies inkrementell. Sie behandeln jeden LTS-Release als stabilen Haltepunkt, sichern die Fortschritte und machen weiter. Teams, die scheitern, versuchen den vollständigen Sprung und stellen fest, dass ihre 40.000 Zeilen umfassende Codebasis keine saubere Schnittlinie hat.
Dieser Leitfaden beschreibt eine schrittweise Migrationsstrategie: warum du bei 4.4 LTS und 6.4 LTS haltmachst, was an jeder Grenze bricht, und wie du die Arbeit so strukturierst, dass dein Produkt weiter ausgeliefert wird, während die Migration läuft.
Warum du nicht direkt zu Symfony 7 springen kannst
Symfonys Deprecation-Modell ist der Kerngrund dafür. Jede Major-Version entfernt alles, was in der vorherigen Minor-Serie als deprecated markiert wurde. Symfony 3.4 ist der Deprecation-Spiegel von Symfony 4.0: Alles, was in 3.x deprecated wurde, wird in 4.0 entfernt. Symfony 4.4 ist der Spiegel von 5.0, und Symfony 6.4 ist der Spiegel von 7.0.
Wenn du auf Symfony 2.8 oder 3.4 bist, nutzt dein Codebase fast sicher APIs, die in Symfony 4.0 entfernt wurden. Der Service-Container, die Security-Firewall-Konfiguration, die Form-Extension-Architektur, der Event-Dispatcher, das YAML/XML-Routing-Format - all diese wurden zwischen Major-Versionen grundlegend verändert. Du kannst diese nicht bei Symfony 7.0 beheben; du behebst sie an jeder Zwischengrenze, wo das Framework noch läuft, aber laut mitteilt, was in der nächsten Major-Version brechen wird.
Der praktische Migrationspfad sieht so aus:
- Symfony 2.x oder 3.x zu 3.4 LTS (alle Deprecations bereinigen, noch auf 3.x)
- Symfony 3.4 zu 4.4 LTS (PHP 7.1+ erforderlich; Flex einführen, Bundle-Entfernung behandeln, DI-Konfiguration anpassen)
- Symfony 4.4 zu 6.4 LTS (PHP 8.1+ erforderlich; neues Security-System, typisierte Properties, attributbasiertes Routing)
- Symfony 6.4 zu 7.x (PHP 8.2+ erforderlich; alle 6.x-Deprecations entfernen, Typsignaturen verfeinern)
Jeder Schritt hat einen klar definierten Umfang. Jeder LTS-Release ist eine stabile Plattform, auf der du pausieren, in Produktion laufen und das Team erholen lassen kannst, bevor der nächste Abschnitt beginnt.
Schritt 1: Zuerst Symfony 3.4 LTS erreichen
Wenn du auf einem 2.x oder einem frühen 3.x-Release bist, besteht die erste Aufgabe darin, 3.4 LTS zu erreichen - den letzten Release vor der 4.x-Grenze. Symfony 3.4 läuft minimal mit PHP 5.5.9, obwohl Produktionsdeployments schon aus Performance- und Sicherheitsgründen auf PHP 7.x laufen sollten.
Bei 3.4 aktivierst du den Deprecation-Handler in deiner Testumgebung. Symfony liefert einen DebugClassLoader und die Umgebungsvariable SYMFONY_DEPRECATIONS_HELPER für PHPUnit mit. Setze sie auf max[total]=0 und führe deine gesamte Testsuite aus. Jeder Deprecation-Hinweis ist ein Arbeitspaket für die 4.0-Grenze.
Die häufigsten Symfony-3.x-Deprecations, die das 4.0-Upgrade blockieren, sind: die Nutzung der deprecated AbstractController-Elternkette, Bundle-Vererbung (ein in 4.0 entferntes Muster), Controller als Services über den alten container-Shortcut, Form-Event-Listener mit entfernten Optionsnamen und eigene Security-Voter, die noch nicht auf die moderne Signatur supports() und voteOnAttribute() umgestellt wurden. Behebe all das, bevor du die Versionseinschränkung in der composer.json änderst.
Schritt 2: Der Symfony-4.4-LTS-Sprung (der schwierigste Schritt)
Der Sprung von 3.4 auf 4.4 ist typischerweise der störendste Abschnitt einer Symfony-2-zu-7-Migration. Drei Veränderungen verursachen die größte Reibung: der Wechsel zu Symfony Flex, die Entfernung der Bundle-Vererbung und die Einführung von Autowiring und Autokonfiguration als Standards.
Symfony Flex und die neue Verzeichnisstruktur. Symfony 4 führte ein neues Application-Skeleton mit deutlich anderem Layout ein. Das Verzeichnis app/ ist verschwunden; die Konfiguration wandert nach config/, der Kernel nach src/, und die Bundle-Registrierung erfolgt über config/bundles.php statt AppKernel.php. Wenn du eine bestehende Anwendung statt eines frischen Skeletons upgradest, musst du diese Struktur manuell migrieren. Der Flex-Upgrade-Leitfaden in der offiziellen Dokumentation deckt die Verzeichniszuordnung Schritt für Schritt ab.
Bundle-Entfernung. Die Symfony Standard Edition bündelte SwiftmailerBundle, MonologBundle, TwigBundle und andere. Mit 4.x wurden mehrere davon entweder zu eigenständigen Paketen, wurden ersetzt oder erfordern explizite Installation. Noch wichtiger: Wenn deine Anwendung eine eigene Bundle-Hierarchie mit Bundle-Vererbung zum Überschreiben von Templates und Controllern nutzte, existiert dieses Muster in 4.x nicht mehr. Du musst überschriebene Templates nach templates/bundles/ verschieben und alle Controller-Überschreibungen umstrukturieren.
PHP-Versionsanforderung. Symfony 4.4 erfordert mindestens PHP 7.1.3. Wenn dein Server noch PHP 5.6 oder 7.0 betreibt, muss das PHP-Upgrade vor oder parallel zur Symfony-4.4-Migration erfolgen. Dies ist typischerweise eine Infra-Aufgabe, die parallel zur Deprecation-Bereinigung läuft.
Die Veränderungen am Security-Komponent. Symfony 4.x begann, die alten Authentication-Provider zugunsten des neuen Authenticator-basierten Systems zu deprecaten, das in 5.x zum Standard wurde. Wenn deine Anwendung ein eigenes Authentication-System hat - in Symfony-2/3-Anwendungen häufig -, plane mindestens einen Sprint für Security-Refactoring in diesem Abschnitt ein.
Nach dem Erreichen von 4.4 pausierst du, deployest auf Staging und lässt die Anwendung mindestens einen Sprint-Zyklus in Produktion einweichen, bevor du weitermachst.
Schritt 3: Symfony 4.4 zu Symfony 6.4 LTS
Der Sprung von 4.4 auf 6.4 ist smoother als der vorherige, aber die PHP-Anforderung ist eine erhebliche Hürde. Symfony 6.x erfordert PHP 8.0 minimal; Symfony 6.4 LTS empfiehlt PHP 8.1 für den vollen Funktionsumfang einschließlich Enums und Fibers. Wenn deine Anwendung noch auf PHP 7.x läuft, ist das PHP-Upgrade der erste Meilenstein in diesem Abschnitt.
Die wirkungsvollste Veränderung zwischen Symfony 4.x und 6.x ist das Security-System. Das Authenticator-basierte Security-Komponent ist in Symfony 6.x der Standard, und der alte form_login-, http_basic- und Custom-Provider-Ansatz wird entfernt. Wenn du eine Legacy-Security-Konfiguration betrieben hast, musst du sie in diesem Schritt neu schreiben. Die neue Architektur ist sauberer und besser testbar, aber die Migration ist nicht mechanisch - sie erfordert ein Verständnis der Authentication-Flows der Anwendung.
Symfony 6.x setzt auch stärker auf PHP-8-Attribute für Routing und Dependency Injection. Du bist nicht gezwungen, sie zu nutzen, aber wenn deine Controller noch @Route-Annotations tragen, wirst du in 6.4 Deprecation-Warnungen sehen, die auf die attributbasierten Alternativen hinweisen. Dies ist ein guter Zeitpunkt für den Wechsel, besonders wenn der Codebase bereits auf PHP 8.1 läuft.
Doctrine ORM ist ein weiterer Bereich zum Prüfen. Symfony 6.4 funktioniert mit ORM 2.x und 3.x, aber die Mapping-Konfiguration und Query-Builder-API haben sich weiterentwickelt. Wenn deine Entities XML-, YAML- oder Annotation-Mapping verwenden, validiere deren Kompatibilität mit der Ziel-doctrine/orm-Version, bevor du Symfony upgradest.
Nach dem Erreichen von 6.4 LTS führe erneut die vollständige Deprecation-Prüfung aus:
bin/console debug:container --deprecations
Jeder Eintrag in dieser Ausgabe ist eine konkrete Aufgabe für den letzten Schritt. Symfony 6.4 ist genau aus diesem Grund die vorgesehene Brücke zu 7.0: Es legt alle 7.0-Entfernungen als Warnungen offen, während die Anwendung voll funktionsfähig bleibt.
Schritt 4: Symfony 6.4 zu Symfony 7.x
Der Sprung von 6.4 auf 7.0 ist der mechanischste der vier Abschnitte, vorausgesetzt du hast das 6.4-Deprecation-Log bereinigt. PHP 8.2 ist erforderlich; PHP 8.3 wird empfohlen. Wenn du während des 6.4-LTS-Lebenszyklus durchgehend Deprecations behoben hast, ist dieser letzte Schritt typischerweise ein Composer-Versions-Bump gefolgt von einer gezielten Analyse von Typsignatur-Abweichungen.
Die häufigsten Probleme an dieser Grenze sind: strengere Methodensignaturen in erweiterten Framework-Klassen (Voter, Event-Subscriber, Form-Types), die Entfernung der letzten Legacy-Security-Aliases und strengere Constructor-Promotion-Anforderungen bei einigen Symfony-Komponenten. Die offizielle Datei UPGRADE-7.0.md im Symfony-Repository listet jede Veränderung auf; sie vor dem Versions-Bump zu lesen ist die beste Zeitinvestition in diesem Abschnitt.
Führe die Testsuite unmittelbar nach dem Versions-Bump aus und bearbeite Fehler nach Schweregrad. Integrationstests, die vollständige Request-Zyklen abdecken, fangen die realistischsten Probleme auf. Unit-Tests einzelner Klassen bestehen oft, auch wenn die Verbindungen zwischen ihnen nicht funktionieren.
Features während einer mehrjährigen Migration weiter ausliefern
Der häufigste Fehler bei Legacy-Symfony-Upgrade-Projekten ist das Stoppen der Feature-Entwicklung, während die Migration läuft. Bei einem Codebase jeder bedeutenden Größe ist das nicht akzeptabel. Die Migration muss parallel zum Produkt laufen.
Der praktische Ansatz ist das Strangler-Fig-Pattern, angewendet auf Symfony-Anwendungsebene. Neue Features werden so entwickelt, dass sie mit der aktuellen und der Ziel-Framework-Version kompatibel sind. Ein Service, der für Symfony 4.4 entwickelt wurde, kann auf 6.4 laufen, wenn er deprecated APIs vermeidet. Ein neuer Controller, der mit Attributen statt Annotations geschrieben wurde, funktioniert auf beiden, wenn die Symfony-Version beide unterstützt.
In der Praxis bedeutet das eine strikte Regel während der Migrationsperiode: Kein neuer Code darf deprecated APIs verwenden. Die Migrationsarbeit - das Beheben alter deprecated Nutzungen - ist ein separater Track von Feature-Arbeit. Beide Tracks werden geschätzt und geplant. Keiner blockiert den anderen.
Für größere Teams funktioniert ein Branch-basierter Ansatz: Ein lang laufender symfony-migration-Branch, der Cherry-Picks von Nicht-Migrations-Features erhält und die Migrationsarbeit inkrementell zurückmergt. Für kleinere Teams geben Feature-Flags an neuen Services - beide Implementierungen hinter einem Toggle laufen - einen risikoärmeren Mechanismus, um migrierten Code zu testen ohne harte Umstellung.
Wenn der Sprung zu weit ist: Parallele Framework-Strategien
Einige Anwendungen haben Schichten, die schlicht inkompatibel mit den Zwischensymfony-Versionen sind. Ein stark angepasstes Bundle, das interne Symfony-APIs nutzt, die in 4.0 entfernt wurden, ein Custom-Authentication-Provider mit tiefen Kernel-Event-Hooks, oder eine Form-Extension, die gegen Symfony-2-era-Interfaces gebaut wurde - diese können den inkrementellen Pfad teurer machen als eine alternative Strategie.
In diesen Fällen ist ein paralleler Framework-Ansatz einen Blick wert: Die alte Symfony-Anwendung parallel zu einem sauberen Symfony-7-Skeleton betreiben und Endpoints einzeln über einen Reverse-Proxy oder eine gemeinsame Datenbankschicht migrieren. Neue Arbeit erfolgt in der modernen Anwendung; Legacy-Routen werden nach Priorität migriert und die alte Anwendung wird außer Betrieb genommen, sobald die letzte Route bestätigt ist.
Diese Strategie kostet mehr im Aufbau, vermeidet aber das Szenario, in dem ein inkompatibles Bundle die gesamte Migration monatelang als Geisel hält. Sie funktioniert am besten, wenn die Anwendung klare Bounded Contexts hat - eine Public-API, ein Admin-Backend, ein Background-Job-System - die unabhängig migriert werden können.
Eine Anmerkung zu PHP-Versionen und technischen Schulden
Eine Symfony-2- oder 3-Anwendung, die noch nie modernisiert wurde, läuft fast sicher auf einer PHP-Version, die ihr End-of-Life erreicht hat. PHP 5.6 erreichte EOL im Dezember 2018. PHP 7.4 beendete den Support im November 2022. Das Laufen auf einer nicht unterstützten PHP-Version ist ein Sicherheitsrisiko, unabhängig von der Symfony-Version.
Plane das PHP-Upgrade als Voraussetzung für die Symfony-Migration, nicht als Nachgedanken. Die sicherste Reihenfolge ist: zuerst PHP-Upgrade (mit einer Symfony-Version, die sowohl die alte als auch die neue PHP-Version unterstützt), dann Symfony-Upgrade. Symfony 3.4 auf PHP 7.4 zu betreiben ist ein gültiger Zwischenzustand, der die PHP-technischen Schulden abbaut, bevor die Framework-Arbeit beginnt.
Für Anwendungen, bei denen eine vollständige Migration noch nicht finanziert ist, ist der minimal vertretbare Zustand PHP 8.1 und Symfony 6.4 LTS, das bis November 2027 Sicherheitsfixes erhält. Das gibt eine bedeutende Startbahn, um die 7.x-Migration zu planen, ohne die Anwendung auf einer nicht unterstützten Plattform zu belassen.
Was eine Legacy-Symfony-Migration zum Erfolg führt
Nach vielen dieser Migrationen sind die Muster, die Erfolg zuverlässig voraussagen, genauso organisatorisch wie technisch. Teams, die erfolgreich sind, behandeln die Migration als Produktinitiative mit expliziten Meilensteinen, nicht als Hintergrundingenieurarbeit, die erledigt wird, wenn Kapazität vorhanden ist. Sie definieren "fertig" für jeden LTS-Schritt - null Deprecation-Warnungen, vollständige Testsuite besteht, in Produktion deployed - bevor sie den nächsten Abschnitt beginnen.
Der Symfony-Codebase wird sich nicht selbst migrieren. Aber der Pfad ist klar definiert, die LTS-Releases sind zuverlässige Haltepunkte, und der Aufwand ist vollständig vorhersehbar, wenn du von einem klaren Deprecation-Inventar an jeder Grenze startest.
Wenn du auf eine Symfony-2- oder 3-Codebasis schaust und fragst, wo du anfangen sollst, lautet die Antwort immer gleich: Führe den Deprecation-Report aus, quantifiziere die Arbeit, um 3.4 sauber zu erreichen, und mache das zum ersten Meilenstein. Alles andere ergibt sich daraus.
Wenn dein Team eine Legacy-Symfony-Migration vor sich hat und erfahrene Unterstützung benötigt - ob für den vollständigen Mehrversions-Pfad oder eine spezifisch schwierige Grenze - melde dich unter hello@wolf-tech.io oder besuche wolf-tech.io/services/legacy-code-optimization, um mehr über unseren Ansatz zur Legacy-Modernisierung zu erfahren.
