PHP · News
PHP 8.6 im Überblick: Partial Application, Time\Duration und 30 Deprecations vor PHP 9.0
PHP 8.6 erscheint am 19.
November 2026 mit partieller Funktionsanwendung, der Klasse Time\Duration und rund dreißig Deprecations, die den Weg zu PHP 9.0 skizzieren. Ein Überblick fasst Features, Migrationsarbeit und den Nutzen von E_DEPRECATED zusammen.
PHP 8.6 ist für den 19. November 2026 geplant. Der Funktionsumfang steht seit Beta 3 fest, und das Release fällt kleiner aus als 8.5: kein JIT, keine Property Hooks, kein neues Typsystem. Ein Überblick von Autor drapic88 argumentiert, das Upgrade selbst dauere einen Nachmittag, die eigentliche Arbeit stecke in den Deprecations, denn die meisten werden in PHP 9.0 zu harten Fehlern.
Das zentrale Feature ist partielle Funktionsanwendung, angenommen mit 33 zu 0 Stimmen. Ein Aufruf mit Platzhaltern liefert eine Closure, die auf die restlichen Argumente wartet: ? steht für genau ein Argument, ... sammelt alle verbleibenden Parameter, und benannte Platzhalter erlauben es, die Signatur der resultierenden Closure umzusortieren. Das ergänzt den Pipe-Operator aus PHP 8.5: Statt jeden Schritt in fn($s) => ... zu verpacken, liest sich eine Pipeline als trim(?) |> str_replace(' ', '-', ?) |> mb_substr(?, 0, 50). Zwei Fallstricke sind wichtig. Argumente in einem Partial werden beim Erzeugen ausgewertet, nicht beim Aufruf, anders als bei Arrow Functions. Und PFA funktioniert nicht bei new, bei __get/__set oder bei scope-lesenden Funktionen wie compact(), extract() und func_get_arg(). Ein positionales ? nach einem benannten Argument ist ein Fatal Error. Anders als First-Class Callables aus 8.1 bewahrt ein Partial nur die Attribute #[\NoDiscard] und #[\SensitiveParameter].
Die zweite Neuerung ist final readonly class Time\Duration, angenommen mit 35 zu 1. Sie beendet zwei Jahrzehnte inkonsistenter Timeout-Einheiten bei sleep(), usleep(), stream_set_timeout(), cURL und Redis-Clients. Die Fabrikmethoden umfassen fromNanoseconds(), fromMicroseconds(), fromMilliseconds(), fromSeconds(int $s, int $ns = 0), fromMinutes(), fromHours() und fromIso8601DurationString(). Instanzen bieten add(), sub(), multiplyBy(int), divideBy(int), negate(), absolute(), ein statisches compare() und die readonly Properties $seconds, $nanoseconds und $negative. Monate und Jahre fehlen bewusst; Kalenderarithmetik bleibt Aufgabe von DateInterval. Erster Core-Konsument ist IO\Poll\Context::wait(?Time\Duration $timeout). Welche bestehenden Core-Funktionen im Release Duration akzeptieren, war während der Entwicklung noch im Fluss.
PHP 8.6 bringt außerdem eine Low-Level-API für I/O-Multiplexing: IO\Poll\Context, StreamPollHandle und Event::Read. Anwendungscode wird sie selten direkt nutzen, aber ReactPHP, Amp, Swoole und FrankenPHP-artige Runtimes implementieren Polling derzeit jeweils selbst. Ein Core-Primitiv könnte asynchrones PHP langfristig vereinheitlichen.
Kleinere Neuerungen: clamp(), auch für Strings; Default-Werte für readonly Properties; #[\Override] für Klassenkonstanten; ein eingebautes SortDirection-Enum mit Ascending und Descending; __debugInfo() für Enums; Doc-Kommentare an Parametern; Fehlermeldungen mit Funktionsargumenten und genaueren json_decode()-Positionen; scope-aware Reflection isReadable() und isWriteable(); Closure-Optimierungen; die Endianness-Modifikatoren < und > in pack()/unpack() für Floats und vorzeichenbehaftete Integer; dazu grapheme_strrev(), mysqli_quote_string(), Locale::getDisplayKeyword(), IntlNumberRangeFormatter, TLS Session Resumption und 0-RTT Early Data für Streams, Pdo\Pgsql::ATTR_CHUNK_SIZE, gmp_powm_sec(), gmp_prevprime(), finfo_file() über Remote-Streams und URI-Builder-Klassen.
Ebenso aufschlussreich sind die Ablehnungen: Pipe-Zuweisung (|>=), das let-Konstrukt (let ist aber reserviert), Bound-erased Generics, __exists(), mehrere Array-Helfer und das Neuzuweisen promoteder readonly Properties wurden abgelehnt. Die Abschaffung von list() scheiterte mit 23 zu 23 Stimmen. Function Autoloading und BackedEnum::values() haben den Zug verpasst; ReflectionAttribute::getCurrent() war zur Beta noch in der Abstimmung.
Für die Migration empfiehlt der Artikel eine feste Reihenfolge. Zuerst die Testsuite mit error_reporting=E_ALL und display_errors=1 laufen lassen, denn CI, das E_DEPRECATED unterdrückt, verschweigt den tatsächlichen Aufwand. Zweitens mechanische Umbenennungen: is_double() zu is_float(), is_integer()/is_long() zu is_int(), doubleval() zu floatval(), spl_object_hash() zu spl_object_id(), spl_classes() zu Reflection, strcoll() und SORT_LOCALE_STRING zum intl Collator, metaphone() zu soundex(), und der $case_insensitive-Flag von define() fällt weg. Drittens keine Objekte mehr an array_walk(), array_walk_recursive(), deflate_init(), inflate_init(), mb_convert_variables() und http_build_query() übergeben; die Lösung ist meist get_object_vars($obj). Ebenfalls deprecated: is_a() und is_subclass_of() mit String als erstem Argument, die CSV-Methoden von SplFileObject und unvollständige session_set_save_handler()-Implementierungen. Viertens Bezeichner freimachen: readonly als Funktionsname, is und let als Identifier, namespace als Klassenkonstante und _ als Konstante sind deprecated, is wird für künftiges Pattern Matching reserviert. Fünftens ist die mb_ereg*-Familie in 8.6 deprecated und wird in 9.0 entfernt, weil Oniguruma seit dem 24. April 2025 keine Upstream-Pflege mehr erhält; die Migration auf preg_* mit u-Modifier braucht Zeit, wie ein offenes Drupal-Issue zeigt. Sechstens stille Verhaltensänderungen: Session-Defaults werden session.use_strict_mode=1, session.cookie_httponly=1 und session.cookie_samesite="Lax"; Rückgaben aus __construct(), __destruct() oder finally sind deprecated; trim() und Verwandte entfernen jetzt Form Feed; viele Funktionen werfen statt zu warnen; preg_grep() liefert false bei Fehlern; ?? und empty() lösen __get() nicht mehr aus, nachdem __isset() eine Property materialisiert hat.
Der Autor schätzt den Aufwand für eine gut getestete Laravel- oder Symfony-App auf 8.4+ auf einen halben bis ganzen Tag, größtenteils Warten auf Abhängigkeiten. Rectors PHP_86-Set, PHPStan oder Psalm und composer why erledigen das meiste. Ein Legacy-Codebestand mit mb_ereg ist ein anderes Gespräch.
Leserforum
Noch keine Beiträge — eröffne die Debatte.
Starte die Diskussion
Kein Konto, kein Passwort nötig — gib einfach deine E-Mail-Adresse ein, wir senden dir einen einmaligen Anmelde-Link. Beim ersten Mal bist du damit automatisch angemeldet.
Deine Bewertung wird nach der Anmeldung automatisch übernommen.
Schau in dein Postfach
Wir haben einen Anmelde-Link an … gesendet. Öffne ihn auf diesem Gerät — dieser Tab meldet dich automatisch an.
Nichts angekommen? Wirf einen Blick in den Spam-Ordner — und markiere die Mail dort als „Kein Spam“, dann landet sie künftig direkt im Postfach.