PHP 7.4 hat seit November 2022 keine Sicherheitsupdates mehr bekommen. Wenn Ihre Anwendung heute noch darauf läuft, sind das über drei Jahre ohne Patches. Das ist kein Vorwurf. Ich sehe solche Systeme ständig. Sie laufen, sie verdienen Geld, und niemand fasst sie freiwillig an.
Irgendwann kommt der Moment, an dem das Upgrade nicht mehr aufschiebbar ist. Der Hoster kündigt die alte PHP-Version ab. Ein Audit bemängelt die EOL-Version. Eine Composer-Abhängigkeit lässt sich nicht mehr aktualisieren, weil sie PHP 8 voraussetzt. Oder ein neuer Entwickler weigert sich schlicht, mit einem Stack von 2019 zu arbeiten.
Dieser Artikel beantwortet die Frage, die vor jedem dieser Projekte steht: Was kommt bei einem Sprung von PHP 7.4 auf PHP 8.4 konkret auf uns zu? Nicht als Marketing-Text, sondern als Erfahrungsbericht aus Projekten, in denen ich genau diese Migrationen durchgeführt habe.
Warum PHP 8.4 als Ziel
Kurz zur Einordnung. PHP 8.4 ist im November 2024 erschienen und bekommt Sicherheitsupdates bis Ende 2028. Wer heute migriert, kauft sich damit mehrere Jahre Ruhe. PHP 8.5 ist zwar bereits draußen, aber für ein Legacy-Upgrade ist 8.4 aus meiner Sicht das pragmatische Ziel: Das Ökosystem hat sich eingependelt, die relevanten Frameworks und Bibliotheken unterstützen es stabil, und die Deprecations sind bekannt und dokumentiert.
Und ja, es gibt einen Performance-Bonus. Je nach Workload laufen Anwendungen auf PHP 8.x spürbar schneller als auf 7.4, oft im Bereich von 10 bis 20 Prozent, ohne dass Sie eine Zeile Code anfassen. Das ist ein netter Nebeneffekt. Der eigentliche Grund für das Upgrade ist er nicht. Der eigentliche Grund ist, dass Sie auf einer Version ohne Sicherheitsupdates sitzen.
Fünf Major-Versionen in einem Sprung
Von 7.4 auf 8.4 überspringen Sie fünf Releases: 8.0, 8.1, 8.2, 8.3 und 8.4. Jedes davon bringt eigene Breaking Changes und Deprecations mit. Das klingt dramatischer als es ist. In der Praxis verteilen sich die Probleme sehr ungleich. Ein paar Änderungen verursachen 80 Prozent der Arbeit. Die kenne ich inzwischen auswendig.
PHP 8.0: Die härteste Stufe
PHP 8.0 ist der Bruch, der wehtut. Drei Dinge treffen Legacy-Code fast immer.
Erstens: Interne PHP-Funktionen werfen bei falschen Argumenten jetzt einen TypeError statt einer Warning. Code, der vorher mit einer Warnung im Log weitergelaufen ist, bricht jetzt hart ab. Das ist gut für die Codequalität und schlecht für den ersten Deployment-Versuch.
Zweitens: Der Vergleich zwischen Strings und Zahlen wurde geändert. 0 == "foo" war in PHP 7.4 wahr. In PHP 8 ist es falsch. Das ist die gefährlichste Änderung im ganzen Upgrade, denn sie produziert keinen Fehler. Der Code läuft weiter, aber ein if-Zweig verhält sich plötzlich anders. Dazu später mehr.
Drittens: Alte Konstrukte sind endgültig weg. each(), create_function(), der Zugriff auf String-Zeichen per geschweifter Klammer wie $str{0}. In Codebasen, die vor 2015 gestartet sind, finde ich davon regelmäßig Dutzende Stellen.
PHP 8.1: Die Deprecation-Flut
PHP 8.1 hat eine unscheinbare Änderung, die in Legacy-Projekten die Logs flutet: Die Übergabe von null an nicht-nullable Parameter interner Funktionen ist deprecated. Klingt akademisch. Praktisch bedeutet es: Jedes htmlspecialchars($row['name']), bei dem der Wert aus der Datenbank null sein kann, erzeugt jetzt eine Deprecation-Meldung. In einem typischen Shop oder CMS sind das schnell tausende Stellen. Noch läuft der Code. In einer künftigen PHP-Version wird daraus ein Fehler.
PHP 8.2: Dynamische Properties
PHP 8.2 deklariert dynamische Properties als deprecated. Also das Muster, bei dem einem Objekt zur Laufzeit einfach eine Eigenschaft zugewiesen wird, die in der Klasse nie deklariert wurde. Alter PHP-Code lebt davon. ORMs, selbstgebaute Datencontainer, Konfigurationsobjekte. Es gibt das Attribut #[AllowDynamicProperties] als Übergangslösung, aber das ist ein Pflaster, kein Fix. Zusätzlich sind utf8_encode() und utf8_decode() deprecated, die in altem Code gern als vermeintliche Allzweckwaffe für Encoding-Probleme missbraucht wurden.
PHP 8.3 und 8.4: Der ruhigere Teil
PHP 8.3 ist für Migrationen die entspannteste Stufe. PHP 8.4 bringt dann noch eine Änderung mit Breitenwirkung: implizit nullable Parameter sind deprecated. Eine Signatur wie function speichern(string $name = null) war jahrelang üblich und muss jetzt explizit ?string $name = null heißen. Das ist mechanisch gut zu beheben, betrifft aber viele Dateien auf einmal.
Was PHP 8.0 bis 8.4 an neuen Features mitbringt, Enums, readonly Properties, Property Hooks, match, Constructor Promotion, lasse ich hier bewusst weg. Für das Upgrade selbst sind neue Features irrelevant. Sie sind die Belohnung danach, nicht die Aufgabe davor.
Die drei Fehlerklassen, und warum nur eine davon gefährlich ist
Wenn ich ein Upgrade-Projekt bewerte, sortiere ich alle Probleme in drei Klassen.
Die erste Klasse sind fatale Fehler. Entfernte Funktionen, entfernte Syntax, TypeErrors. Diese Klasse ist laut und deshalb harmlos. Statische Analyse findet sie vor dem Deployment, und was durchrutscht, knallt sofort und sichtbar. Ein Fehler, der sofort auffällt, ist ein billiger Fehler.
Die zweite Klasse sind Deprecations. Auch die sind laut, nur eben im Log statt im Browser. Sie zwingen nicht zum sofortigen Handeln, aber wer sie ignoriert, verschiebt das Problem nur auf das nächste Upgrade. Ich behebe sie im Rahmen der Migration mit, weil die Werkzeuge dafür ohnehin schon laufen.
Die dritte Klasse sind stille Verhaltensänderungen. Das ist die gefährliche. Der String-Zahlen-Vergleich aus PHP 8.0 ist das Paradebeispiel. Kein Fehler, keine Warnung, kein Log-Eintrag. Nur ein Vergleich, der jetzt anders ausgeht als vorher. Wenn dieser Vergleich in einer Preisberechnung, einer Berechtigungsprüfung oder einem Gutschein-Check steckt, haben Sie ein Problem, das erst der Kunde findet.
Gegen die dritte Klasse hilft keine statische Analyse zuverlässig. Gegen sie helfen Tests. Und genau da liegt das eigentliche Risiko der meisten Legacy-Projekte: nicht im alten PHP, sondern in der fehlenden Testabdeckung.
Wie ich bei so einem Upgrade vorgehe
Der Ablauf ist in jedem Projekt ähnlich, auch wenn die Gewichtung variiert.
Schritt 1: Inventur
Bevor ich Code anfasse, will ich wissen, womit ich es zu tun habe. Welche PHP-Extensions sind installiert und werden wirklich genutzt? Welche Composer-Pakete blockieren PHP 8.4? Ein composer why-not php 8.4 beantwortet das in Sekunden und liefert die Liste der Abhängigkeiten, die zuerst aktualisiert oder ersetzt werden müssen. Dazu kommt die Frage nach dem Framework, dazu gleich mehr.
Am Ende der Inventur gibt es eine ehrliche Liste: Das sind die Blocker, das sind die bekannten Baustellen, das ist der geschätzte Aufwand. Erst danach lässt sich seriös über Timeline und Budget sprechen. Wer Ihnen einen Festpreis nennt, bevor er diese Inventur gemacht hat, rät.
Schritt 2: Statische Analyse und automatisierte Umbauten
Der mechanische Teil der Migration ist heute weitgehend automatisierbar. PHPStan mit dem PHPCompatibility-Regelwerk findet entfernte Funktionen, geänderte Signaturen und die meisten Deprecations. Rector schreibt einen erheblichen Teil der nötigen Änderungen direkt um: nullable Signaturen, entfernte Syntax, triviale Ersetzungen.
Wichtig ist die Reihenfolge. Erst die Analyse mit einer Baseline, damit das bestehende Grundrauschen dokumentiert ist und neue Probleme sichtbar werden. Dann automatisierte Umbauten in kleinen, einzeln reviewbaren Schritten. Ein Rector-Lauf, der 800 Dateien in einem Commit ändert, ist nicht mutig, sondern unreviewbar.
Automatisierung erledigt bei diesen Migrationen realistisch 60 bis 70 Prozent der Codeänderungen. Der Rest ist Handarbeit an genau den Stellen, an denen der Code Annahmen macht, die kein Tool versteht.
Schritt 3: Tests dort, wo es wehtut
Die wenigsten Legacy-Projekte haben eine Testabdeckung, die den Namen verdient. Das komplette Nachrüsten von Tests ist im Rahmen eines Upgrades weder bezahlbar noch nötig. Was ich stattdessen mache: Charakterisierungstests für die kritischen Pfade. Preisberechnung, Checkout, Login, Exporte, Schnittstellen. Diese Tests dokumentieren das Ist-Verhalten unter PHP 7.4 und laufen dann unter PHP 8.4 gegen dieselben Erwartungen.
Das ist die einzige verlässliche Waffe gegen die stillen Verhaltensänderungen. Und diese Tests bleiben nach dem Projekt im Repository. Sie sind der Teil des Budgets, der auch nach dem Upgrade weiter Rendite bringt.
Schritt 4: Stufenweise oder direkt?
Die häufigste technische Frage: Migrieren wir über 8.0, 8.1, 8.2 einzeln, oder direkt auf 8.4? Meine Antwort ist unspektakulär: Der Code wird in einem Zug auf 8.4-Kompatibilität gebracht, aber gegen mehrere Versionen geprüft. Die CI-Pipeline läuft während der Migration gegen PHP 7.4 und PHP 8.4 parallel. So bleibt die Anwendung jederzeit auf der alten Version deploybar, während die neue vorbereitet wird.
Einzeln über jede Zwischenversion zu deployen kostet Zeit und bringt fast nichts. Die Zwischenversionen sind Prüfstationen, keine Zwischenziele.
Schritt 5: Deployment mit Rückweg
Das Deployment selbst ist bei sauberer Vorbereitung der langweiligste Teil, und genau so soll es sein. Neue Umgebung mit PHP 8.4 parallel aufbauen, Traffic umschalten, Fehlerrate und Logs beobachten. Und vor allem: einen getesteten Rückweg haben. Die alte 7.4-Umgebung bleibt stehen, bis die neue sich im echten Betrieb bewiesen hat. Wenn etwas Unerwartetes auftaucht, wird zurückgeschaltet, in Minuten, nicht in einem hektischen Nacht-Einsatz.
Technisch ist das ein Blue/Green-Deployment, und ich behandle den Rückweg als Teil der Lieferung, nicht als Notfallplan. Nicht weil ich damit rechne, ihn zu brauchen, sondern weil ein Upgrade ohne definierten Rückweg schlicht kein professionelles Vorgehen ist.
Das Framework ist oft das eigentliche Projekt
Ein Punkt, der in Angeboten gern unterschlagen wird: Reines PHP-Upgrade und Framework-Upgrade sind zwei verschiedene Projekte, die oft zusammenfallen.
Wer auf PHP 7.4 festhängt, hängt meistens auch auf einer alten Framework-Version fest. Ein Symfony 4, ein TYPO3 9 oder 10, ein Shopware 5, ein altes Zend Framework. Diese Versionen unterstützen PHP 8.4 nicht. Das heißt: Bevor die PHP-Version steigen kann, muss das Framework auf einen Stand, der die Ziel-Version trägt. Bei Symfony ist das ein definierter Upgrade-Pfad über die LTS-Versionen. Bei TYPO3 ebenso, mit den bekannten Major-Sprüngen. Bei Shopware 5 ist es ehrlicherweise eine Plattform-Migration, kein Upgrade. Bei Zend Framework 1 gibt es keinen offiziellen Pfad mehr, dort arbeite ich je nach Fall mit Kompatibilitäts-Shims oder einer schrittweisen Ablösung.
Genau hier entstehen die Aufwandsunterschiede zwischen Projekten. Der PHP-Sprung selbst ist planbar. Die Frage, wie viel Framework-Altlast mitgezogen werden muss, entscheidet über Wochen oder Monate.
Was kostet das, realistisch
Konkrete Zahlen ohne Inventur wären unseriös, aber die Aufwandstreiber kann ich benennen. Es sind nicht die, die man intuitiv erwartet.
Die Größe der Codebasis ist überraschend zweitrangig. 500.000 Zeilen sauberer, getesteter Code migrieren sich schneller als 80.000 Zeilen ohne Tests mit globalem State. Was den Aufwand wirklich treibt: fehlende Testabdeckung, die Menge an dynamischen Properties und ungetypter Datenflüsse, tote Abhängigkeiten ohne PHP-8-Support, Eigenbau-Frameworks und die Frage, ob das Deployment reproduzierbar ist oder auf einem Server lebt, den zuletzt 2021 jemand angefasst hat.
Als grobe Orientierung aus meinen Projekten: Eine mittelgroße Anwendung mit Composer-Setup und halbwegs aktuellem Framework ist ein Projekt von wenigen Wochen. Kommt ein Framework-Major-Upgrade dazu, reden wir über ein bis drei Monate. Eigenbau-Systeme ohne Tests und ohne Paketverwaltung sind Einzelfallbetrachtungen, und genau dort lohnt die Inventur als eigener, kleiner erster Auftrag: überschaubares Budget, und danach wissen beide Seiten, worüber sie sprechen.
Häufige Fragen, kurz beantwortet
Muss die Anwendung während der Migration offline? Nein. Die Migration passiert parallel zum laufenden Betrieb. Die Umschaltung selbst ist ein kurzer, kontrollierter Vorgang mit Rückweg.
Können wir während der Migration weiterentwickeln? Ja, mit Disziplin. Die Migrations-Änderungen laufen in kleinen Schritten in den Hauptzweig, nicht als monatelanger Parallel-Branch. Ein Big-Bang-Branch, der nach drei Monaten gemergt werden soll, ist der zuverlässigste Weg, ein solches Projekt scheitern zu lassen.
Was ist mit PHP 8.5 oder späteren Versionen? Wer den Sprung auf 8.4 sauber gemacht hat, also mit statischer Analyse, CI und Tests auf den kritischen Pfaden, für den sind künftige Versionssprünge Routinewartung statt Projekt. Das ist der eigentliche Wert der Migration: nicht die neue Versionsnummer, sondern dass die nächste keine Angst mehr macht.
Reicht nicht erstmal PHP 8.1 oder 8.2? Technisch geht das, strategisch ist es fast immer ein Fehler. PHP 8.1 bekommt bereits keine Sicherheitsupdates mehr, bei 8.2 endet der Support Ende 2026. Wer jetzt den Migrationsaufwand betreibt, sollte auf eine Version zielen, die noch Jahre getragen wird.
Fazit
Ein Upgrade von PHP 7.4 auf 8.4 ist kein Hexenwerk, aber es ist auch kein Nachmittag mit Suchen-und-Ersetzen. Es ist ein planbares Projekt mit bekannten Stolperstellen: die harten Brüche aus PHP 8.0, die Deprecation-Wellen aus 8.1 und 8.2, die stillen Verhaltensänderungen, gegen die nur Tests helfen, und das Framework als heimlicher Hauptdarsteller.
Wenn Sie eine Anwendung auf PHP 7.4 betreiben und wissen wollen, was der Sprung in Ihrem konkreten Fall bedeutet, ist der erste Schritt keine Angebotsanfrage, sondern eine Inventur. Die mache ich als kompaktes Festpreis-Paket, mit einer ehrlichen Einschätzung von Blockern, Aufwand und Risiken. Danach entscheiden Sie auf Basis von Fakten statt Bauchgefühl.

