Vor Kurzem habe ich das Goal Statement von Rhombus gelesen, einer neuen Programmiersprache, die auf Racket aufbaut. Es beginnt mit einer Frage, die alle beantworten müssen, die eine Programmiersprache entwerfen:
Modern programming languages reflect a consensus on the most important programming concepts, including lexically scoped variables, closures, objects, pattern matching, and type parametricity. Why, then, yet another programming language?
Beyond the basics, there are still more good ideas for programming constructs than can fit in any one language specification. Furthermore, specific domains benefit from language support that is tailored to the domain. Language extensibility helps to balance the competing goals of a manageable language size versus fit-to-purpose for a wide range of tasks.
Diesen Rahmen fand ich nützlich: nicht, um die neue Sprache zu bewerten, sondern die, die ich seit 1998 verwende. PHP ist 31 Jahre alt. Ich bereue nicht, es als meine primäre Sprache gewählt zu haben, und dieser Artikel ist keine Verteidigung dieser Wahl.
Verteidigungen akzeptieren den Rahmen: Sie gestehen zu, dass PHP seine Existenz gegen Erfahrungen rechtfertigen muss, die Menschen vor zwanzig Jahren damit gemacht haben, und verwenden dann zweitausend Wörter darauf, Beschwerden über PHP 4 zu widerlegen. Warrick Bayman hat schon vor Jahren erklärt, warum dieses Genre erschöpft ist. Ich werde nichts dazu beitragen.
Nehmen wir stattdessen die obige Checkliste und stellen eine interessantere Frage: Wie schneidet PHP im Jahr 2026, mit PHP 8.5, das im vergangenen November erschienen ist, und PHP 8.6, das in diesem November erscheint, gegen die Konsenskonzepte des modernen Sprachdesigns ab? Und wie sieht seine Antwort auf die Frage nach der Erweiterbarkeit aus?
Die Checkliste von Rhombus
Lexikalisch gebundene Variablen und Closures
Die Closures von PHP sind lexikalisch gebunden, mit einer Designentscheidung, die die Sprache bis heute von den meisten anderen unterscheidet: Das Einfangen von Variablen ist explizit. Eine mit function () use ($x) deklarierte Closure benennt, was sie einfängt; eine Arrow Function fn () => $x fängt automatisch ein, aber per Wert. Du weißt immer, was die Grenze überquert.
Seit PHP 8.1 lässt sich jede Funktion und jede Methode mit der First-Class Callable Syntax in eine Closure überführen. PHP 8.5 hat Closures auf konstante Ausdrücke ausgeweitet, etwa Argumente von Attributen sowie Standardwerte von Properties und Parametern, und den Pipe-Operator |> eingeführt.
PHP 8.6 vervollständigt das Bild mit partieller Funktionsanwendung: strlen(?) erzeugt eine Closure mit einer Leerstelle, und zusammen mit |> wird daraus echte Funktionskomposition. Dieselbe Version optimiert die zugrunde liegende Implementierung: Closures, die $this nicht verwenden, werden als statisch erkannt, und vollständig zustandslose Closures werden zwischen Verwendungen gecacht.
In dieser Reihenfolge nimmt eine Sprache ein Konzept ernst: zuerst die Semantik, dann die Ergonomie, zuletzt die Performance.
Objekte
Das Objektsystem ist mit Abstand der vollständigste Teil der Sprache. Enumerationen, readonly Properties, Constructor Promotion, Property Hooks und asymmetrische Sichtbarkeit (PHP 8.4), clone with und finale Promoted Properties (PHP 8.5), #[\Override] erweitert auf Klassenkonstanten (PHP 8.6).
Eine in modernem PHP geschriebene Klasse drückt ihre Absicht in der Deklaration selbst aus, zur Laufzeit von der Engine geprüft: was unveränderlich ist, was berechnet wird, was eine Unterklasse ersetzen darf. Wer seine Vorstellung von PHP-Objekten in Zeiten von var $foo gewonnen hat, würde die Sprache nicht wiedererkennen.
Pattern Matching
Heute ein halber Punkt, aber mit einer konkreten Perspektive.
match ist seit PHP 8.0 ein Ausdruck mit strikter Vergleichssemantik und hat eine ganze Klasse von switch-Fehlern beseitigt. Aber es vergleicht Werte, keine Strukturen: kein Destructuring, kein Binden von Variablen, keine Vollständigkeitsprüfung über Shapes.
Diese Lücke adressiert nun der Pattern Matching RFC von Larry Garfield und Ilija Tovilo, der mit einer funktionierenden Implementierung zur Diskussion steht. Er führt is als Vergleichsoperator über Patterns ein:
- Type Patterns:
$value is int|float - Object Patterns mit Property-Vergleich und Variablenbindung:
$p is Point(x: 3, y: $y) - Array Shapes:
$request is ['action' => string, 'id' => int, ...]
Mit match ($value) is { ... } bekommen wir eine Struktur, mit der wir diese Patterns und Shapes kombinieren können.
Der RFC versteht sich ausdrücklich als Zwischenschritt zu algebraischen Datentypen (Enumerationen mit assoziierten Werten), die den Abstand zum Konsens vollständig schließen würden. Das Zeitfenster für neue Features in PHP 8.6 hat der RFC verpasst; ich gehe davon aus, dass er mit PHP 8.7 im Jahr 2027 ausgeliefert wird. Bis dahin bleibt dies das Konzept, bei dem PHP am weitesten zurückliegt, und das darf ruhig deutlich gesagt werden, ebenso wie die Tatsache, dass sich der verbleibende Abstand inzwischen in einem Release-Zyklus bemisst, nicht im Prinzip.
Typparametrisierung
Die ehrliche Antwort ist nein, und die interessante Antwort ist komplizierter.
PHP hat keine Generics in der Sprache, und die Internals-Community hat das kürzlich bekräftigt, als ein Vorschlag für Bound-Erased Generics für PHP 8.6 abgelehnt wurde. Es lohnt sich zu verstehen, warum er abgelehnt wurde, denn der Grund ist nicht Gleichgültigkeit gegenüber Generics. Wie Gina Banyard argumentiert, richtet sich der Einwand gegen die Erasure, nicht gegen die Parametrisierung.
Jede Typdeklaration, die PHP je bekommen hat, wird zur Laufzeit geprüft, von den Klassentypen in PHP 5.0 über die skalaren Typen in PHP 7.0 bis heute, und native Syntax einzuführen, die stillschweigend nicht geprüft wird, würde diese Invariante brechen, denn die meisten Entwicklerinnen und Entwickler gehen, wenn sie die Syntax sehen, davon aus, dass sie durchgesetzt wird. Erasure funktioniert beispielsweise in den Sprachen Java und TypeScript. Diese Sprachen kombinieren die Funktion mit einem verpflichtenden, separaten Compile-Schritt, der die Typen prüft, bevor die Ausführung beginnt.
PHP hat keinen solchen Schritt, und die Prämisse, dass „sowieso alle statische Analyse verwenden“, übersteht den Kontakt mit der Realität nicht: Das JetBrains Developer Ecosystem Survey verortet die Verbreitung von PHPStan und Psalm, wohlwollend zusammengerechnet, deutlich unter der Hälfte der PHP-Entwicklerinnen und -Entwickler. Die Ablehnung der Erased Generics war ein Votum für Kohärenz.
Der Weg, den Banyard stattdessen skizziert, graduelle und zur Laufzeit geprüfte Generics, die mit invarianten Typparametern auf Interfaces wie ArrayAccess<int, Animal> beginnen und für die sie einen funktionierenden Prototyp hat, ist genau der Weg, auf dem das Typsystem von PHP schon immer gewachsen ist: ein geprüfter Schritt pro Version, von Klassentypen in PHP 5.0 bis zu DNF-Typen in PHP 8.2.
Unterdessen verwendet jede nicht-triviale PHP-Codebasis, der ich begegne, längst Generics: list<Order>, array<string, Money>, Collection<T>, Template-Kovarianz, bedingte Typen. Sie leben in einer Typsprache, die der PHP-Interpreter weder definiert noch prüft: dem Docblock-Dialekt, den PHPStan und Psalm interpretieren, der in der CI durchgesetzt und von jeder IDE verstanden wird. Und für den häufigsten Anwendungsfall, typsichere Collections, brauchst du nicht einmal auf Generics zu warten.
Erweiterbarkeit, aus Versehen
Womit ich zurück bei Rhombus bin. Seine Antwort auf „Warum noch eine weitere Sprache?“ ist Erweiterbarkeit, eine glaubwürdige Antwort aus dieser besonderen Ecke der Welt, denn Rhombus baut auf Racket auf, dem am radikalsten erweiterbaren Sprachökosystem, das es gibt: Halte die Spezifikation klein und lass sie von denen, die sie nutzen, in Richtung ihrer Domäne erweitern. PHP hat keine Makros, keine benutzerdefinierte Syntax, keinen erweiterbaren Reader. Nach den Kriterien von Rhombus müsste es in der Wahl zwischen einer aufgeblähten Spezifikation und schlechter Passgenauigkeit feststecken.
Es ist durch eine Seitentür entkommen. Die Typsprache der statischen Analyse ist der Erweiterungsmechanismus von PHP: ein vollständiges, ausdrucksstarkes Typsystem im User Space, das über den graduellen Typen der Laufzeit liegt und sich im Release-Takt von Werkzeugen weiterentwickelt statt im Release-Takt einer Sprachspezifikation mit einem Versprechen der Rückwärtskompatibilität.
Du kannst beklagen, dass das „echte“ Typsystem des professionellen PHP eine Konvention zwischen Drittanbieter-Werkzeugen ist. Du kannst aber auch feststellen, dass dieses Arrangement Millionen von Entwicklerinnen und Entwicklern Generics, Shape Types und Refinement Types gebracht hat, ohne eine einzige RFC-Abstimmung und ohne die Engine langsamer oder die Sprache größer zu machen.
Und es funktioniert genau deshalb, weil die Grenze ehrlich ist: Ein Docblock erhebt sichtbar keinen Laufzeitanspruch, während native Syntax mit Erasure denselben Nicht-Anspruch als vermeintliche Zusage tarnen würde, und das ist das Kohärenzargument, an dem die Bound-Erased Generics gescheitert sind.
Die beiden Schichten haben Erfolg, gerade weil sie nicht vorgeben, die jeweils andere zu sein. Attribute sind die zweite Nahtstelle: ein sanktionierter Haken für Metaprogrammierung, über den Frameworks Domänensemantik wie Routing, Validierung und objektrelationale Abbildung anbinden, ohne neue Syntax. Die Spezifikation blieb überschaubar; die Passgenauigkeit kam von außerhalb.
Das Bekenntnis zur Domäne
Das Goal Statement von Rhombus stellt eine zweite Behauptung auf: Bestimmte Domänen profitieren von Sprachunterstützung, die auf die Domäne zugeschnitten ist. PHP ist der stärkste existierende Beleg für diese Behauptung, denn es hat den entgegengesetzten Trade-off zur Erweiterbarkeit gewählt: Es hat sich auf eine Domäne festgelegt und sie in die Plattform eingebacken.
Das Shared Nothing-Ausführungsmodell mit Request Scope bleibt die am meisten unterschätzte Eigenschaft von PHP. Jeder Request beginnt in einem sauberen Zustand und endet im Vergessen: Fehlerisolation pro Request, horizontale Skalierung als Standard, keine langsame Ansammlung von korruptem Zustand und eine Speicherverwaltung, die sich größtenteils auf „der Request endet“ reduziert. Das sind Eigenschaften, die andere Ökosysteme aus Frameworks, Konventionen und Betriebsdisziplin zusammensetzen. In PHP sind sie der Boden, auf dem alles steht. Und die Plattform vertieft dieses Bekenntnis weiter.
PHP 8.5 hat eine neue URI-Extension ausgeliefert, mit Semantik sowohl nach RFC 3986 als auch nach dem WHATWG URL Standard: ein wirklich schwieriges Korrektheitsproblem für alles, was mit URLs aus Benutzereingaben in Berührung kommt, jetzt in der Standardbibliothek gelöst.
PHP 8.6 knüpft daran an und härtet die Standardwerte der Session-Konfiguration, womit die sichere Konfiguration zur Standardkonfiguration wird. Dieselbe Version zeigt Funktionsargumente in Fehlermeldungen und baut damit auf den Backtraces für fatale Fehler aus PHP 8.5 auf.
Neben partieller Funktionsanwendung klingt das unbedeutend, aber für eine Sprache, deren primärer Einsatzkontext produktive Web Workloads sind, sind Beobachtbarkeit von Fehlern und sichere Standardwerte Domänenunterstützung in genau dem Sinn, den die Designer von Rhombus meinen.
Und mit jeder Deprecation zahlt die Sprache still die technischen Schulden von 1995 ab: Verlustbehaftete Casts wie (int) "123abc" sind auf dem Weg nach draußen, ein sorgfältig abgestimmter RFC nach dem anderen, in einem jährlichen Release-Rhythmus, der seit einem Jahrzehnt hält.
So sieht Evolution unter einem Versprechen der Rückwärtskompatibilität aus: langsamer als eine Forschungssprache, schneller als ein Standardisierungsgremium und vorhersehbar genug, um ein Upgrade darauf zu planen.
Wo wir stehen
Gemessen an der Checkliste von Rhombus erreicht PHP im Jahr 2026 vier von fünf Punkten:
Pattern Matching mit halber Punktzahl, aber auf einem sichtbaren Weg zur vollen, und die Typparametrisierung vorerst ausgelagert an eine Werkzeugschicht, die schneller iteriert, als die Sprache selbst es je könnte, während Internals daran arbeitet, Generics ohne Erasure in die Sprache zu bringen.
Gemessen am Kriterium der Domänenpassung schneidet es besser ab als Sprachen, die weit mehr bewundert werden: graduelle Typisierung genau an der Grenze, an der HTTP-Eingaben ohnehin untypisiert sind, ein Ausführungsmodell, das wie die Request/Response-Struktur der Domäne geformt ist, und eine Standardbibliothek, die korrektes URL-Parsing und sichere Session-Standardwerte inzwischen von Haus aus mitbringt.
Nichts davon hat von mir verlangt zu argumentieren, dass PHP lebt. Es hat nur verlangt, die Sprache so zu betrachten, wie sie ist, mit den Kriterien, die Sprachdesigner selbst für wesentlich halten, und zu beschreiben, was wir vorfinden.
Was wir vorfinden, ist eine 31 Jahre alte Sprache, die den größten Teil des Konsenses übernommen, eine unkonventionelle Antwort auf die Frage der Erweiterbarkeit gefunden und ihre Domäne nie verlassen hat.
Ich schreibe seit 28 dieser 31 Jahre PHP. Die Sprache, die ich heute verwende, ist besser als die, die ich damals gewählt habe, und sie ist viel, viel besser als die, an die sich die meisten erinnern, die gegangen sind.