PHP 8.6 erscheint am 19. November 2026 und ist das Release, auf das viele Teams bei Callbacks lange gewartet haben. Partial Function Application macht aus fast jeder kleinen Arrow Function einen einzigen Funktionsaufruf mit Platzhalter. Dazu kommen eine eigene Klasse für Zeitdauern, die Funktion clamp(), Readonly Properties mit Defaults, Stream Fehler als Exceptions und eine native Polling API als Fundament für asynchrones PHP. Gleichzeitig ändern sich Session Defaults und viele Funktionen werfen jetzt einen ValueError, wo bisher nur eine Warnung kam. Wir arbeiten täglich mit PHP und Symfony in Production und zeigen hier, was neu ist, was bricht und wie ihr sicher updatet. Den Vergleich aller Versionen seit 8.0 findet ihr in unserem Glossar PHP 8 Versionen im Vergleich.
PHP Update auf 8.6 geplant?
Wir bringen eure Anwendung mit eurem Team auf PHP 8.6. Deprecations lösen wir mit Rector, abgesichert durch PHPStan, PHPUnit und Cypress E2E Tests in der Pipeline.
PHP 8.6 neue Features im Überblick
| Feature | Bereich | Was ihr davon habt |
|---|---|---|
| Partial Function Application | Sprache | Callbacks mit ? statt Arrow Function, ideal mit dem Pipe Operator |
| Time\Duration | Date | Zeitdauern mit Einheit statt nackter int Werte |
| clamp() | Standard | Werte in Grenzen halten ohne min und max Schachtelung |
| Readonly Property Defaults | Sprache | Default Werte direkt an readonly Properties |
| Objekte in Konstanten ändern | Sprache | Properties von Objekten in Konstanten beschreiben |
| #[\Override] für Konstanten | Sprache | Fehler beim Umbenennen von Parent Konstanten fallen sofort auf |
| __debugInfo() auf Enums | Sprache | Lesbare Ausgabe in var_dump() und Debuggern |
| Stream Errors | Streams | Dateifehler als StreamException statt Warnung |
| Polling API | IO | epoll und kqueue nativ für Event Loops |
| SortDirection Enum | Standard | Ein gemeinsamer Typ statt asc und desc Strings |
| URI Builder | URI | URLs bauen statt zusammenkleben |
| Sichere Session Defaults | Session | Strict Mode, HttpOnly und SameSite Lax ab Werk |
Wann erscheint PHP 8.6
Laut offiziellem Zeitplan im PHP Wiki ist die finale Version für den 19. November 2026 geplant. Davor kommt am 5. November noch RC5. Der Hard Feature Freeze war im September, neue Features kommen also nicht mehr dazu. Release Manager sind Daniel Scherzer, Matteo Beccati und Joe Ferguson.
Testet die Release Candidates schon jetzt in eurer CI. Ein zusätzlicher Job mit PHP 8.6 kostet wenig und zeigt Deprecations, bevor sie in Production landen. Wie schnell veraltete PHP Versionen gefährlich werden, haben zuletzt die PHP Sicherheitslücke im Oktober und PHP2Shell gezeigt.
Partial Function Application in PHP 8.6
Das wichtigste Feature von PHP 8.6. Ihr schreibt einen normalen Funktionsaufruf und setzt ? dort ein, wo ein Argument noch fehlt. PHP führt die Funktion dann nicht aus. Ihr bekommt eine Closure zurück, die genau dieses Argument erwartet.
$prices = [19.987, 5.512, 120.049];
// bisher
$rounded = array_map(fn (float $price) => round($price, 2), $prices);
// PHP 8.6
$rounded = array_map(round(?, 2), $prices);
// [19.99, 5.51, 120.05]
Es gibt drei Arten von Platzhaltern:
- ? steht für genau ein Argument an dieser Position.
- … steht für alle restlichen Argumente.
- Benannte Platzhalter wie
flags: ?ersetzen gezielt einen Parameter, auch in anderer Reihenfolge.
Die erzeugte Closure übernimmt Namen, Typen, Defaults und Rückgabetyp der Originalfunktion. Reflection, Dependency Injection Container und statische Analyse sehen also eine echte, typisierte Funktion. Auch #[SensitiveParameter] bleibt erhalten, Passwörter tauchen damit nicht in Stack Traces auf. Für Konstruktoren mit new funktioniert Partial Application nicht, statische Factory Methoden dagegen schon.
Partial Function Application mit dem Pipe Operator
Seit PHP 8.5 gibt es den Pipe Operator |>. Jeder Schritt braucht aber eine Funktion mit genau einem Parameter. Sobald eine Funktion mehr Argumente hatte, landete wieder eine Arrow Function in der Pipe. Mit PHP 8.6 wird das lesbar:
$slug = ' PHP 8.6 Release Notes '
|> trim(...)
|> strtolower(...)
|> str_replace(' ', '-', ?);
// "php-8.6-release-notes"
Steht eine Partial Application mit einem einzigen Platzhalter direkt rechts vom Pipe Operator, optimiert der Compiler die Closure komplett weg. Es entsteht ein direkter Funktionsaufruf ohne Overhead. Alle Details stehen im RFC Partial Function Application v2.
Ein Hinweis aus der Praxis: Argumente einer Partial Application werden sofort ausgewertet, beim Erzeugen der Closure. Bei einer Arrow Function passiert das erst beim Aufruf. Wer teure Funktionen als Argument übergibt, sollte das im Kopf haben.
Time Duration in PHP 8.6
Cache TTL, HTTP Timeout, Retry Delay, Lock Dauer. In fast jedem Projekt stecken Parameter wie int $timeout, und nur der Name verrät die Einheit. Sekunden oder Millisekunden? PHP 8.6 bringt mit Time\Duration eine eigene Klasse für Zeitdauern mit Nanosekunden Genauigkeit.
use Time\Duration;
$retryDelay = Duration::fromMilliseconds(250)->multiplyBy(4);
$retryDelay->seconds; // 1
$lockTime = Duration::fromIso8601DurationString('PT15M');
$lockTime > Duration::fromMinutes(10); // true
$total = $retryDelay->add($lockTime);
Die Klasse ist final readonly, jede Operation liefert ein neues Objekt. Es gibt Konstruktoren von Stunden bis Nanosekunden, dazu add(), sub(), multiplyBy(), divideBy(), negate(), absolute() und compare(). Vergleiche mit < und > funktionieren direkt. Anders als DateInterval kennt Duration keine Tage oder Monate, Sommerzeit spielt also keine Rolle. Laut RFC zur Duration Klasse ist sie der erste Baustein für eine neue Date und Time Bibliothek in PHP.
Die neue Funktion clamp in PHP
Wer Werte in Grenzen halten will, hat bisher max($min, min($max, $value)) geschrieben und dabei gern min und max vertauscht. PHP 8.6 bringt dafür eine eigene Funktion:
$rating = clamp((int) $request->get('rating'), 1, 5);
$discount = clamp($percent, min: 0, max: 100);
clamp('z', 'a', 'm'); // "m"
clamp(10, 20, 5); // ValueError, min ist größer als max
clamp() vergleicht nach den normalen PHP Regeln, funktioniert also auch mit Strings und DateTime Objekten. Ist $min größer als $max oder eine Grenze NAN, gibt es einen ValueError. Wer bisher eine eigene Funktion mit dem Namen clamp im globalen Namespace hatte, muss sie umbenennen. Mehr steht im RFC zu clamp.
Readonly Properties mit Default Werten
Bisher durfte eine readonly Property keinen Default haben. Für DTOs und Value Objects hieß das: Default in den Konstruktor schieben, nur damit die Property readonly bleibt. Ab PHP 8.6 geht es direkt:
final class MailConfig
{
public readonly string $transport = 'smtp';
public readonly int $port = 587;
}
$config = new MailConfig();
$config->port = 25; // Error: Cannot modify readonly property
Details liefert der RFC zu Readonly Property Defaults.
Weitere Sprachfeatures in PHP 8.6
Override Attribut für Konstanten
#[\Override] gibt es für Methoden seit PHP 8.3 und für Properties seit PHP 8.5. Jetzt funktioniert es auch für Klassenkonstanten und Enum Cases. Wird die Konstante in der Elternklasse umbenannt oder gelöscht, meldet PHP das beim Kompilieren.
abstract class Report
{
const FORMAT = 'pdf';
}
final class CsvReport extends Report
{
#[\Override]
const FORMAT = 'csv';
}
Objekte in Konstanten verändern
Seit PHP 8.1 darf eine Konstante ein Objekt enthalten. PHP 8.6 erlaubt jetzt auch, Properties dieses Objekts zu schreiben, zum Beispiel FLAGS->active[] = 'checkout';. Die Konstante selbst bleibt fest, nur das Objekt ändert sich. Enum Cases bleiben unveränderlich.
Debug Ausgabe für Enums
Enums dürfen jetzt __debugInfo() definieren. Damit bestimmt ihr, was var_dump() oder ein Debugger anzeigt. Gibt __debugInfo() irgendwo noch ?array zurück, ist das ab PHP 8.6 deprecated. Schreibt dort array.
SortDirection als gemeinsamer Typ
Das neue globale Enum SortDirection hat die Cases Ascending und Descending. Noch nutzt keine Kernfunktion es. Der Sinn ist ein gemeinsamer Typ für Bibliotheken und Query Builder, damit nicht jedes Paket eigene Strings erfindet. Mehr dazu im RFC zum SortDirection Enum.
Stream Fehler als Exception in PHP 8.6
file_get_contents() auf eine fehlende Datei liefert seit jeher eine Warnung und false. Frameworks bauen dafür eigene Error Handler. PHP 8.6 kann das selbst. Über den Stream Context legt ihr fest, wie Fehler gemeldet werden:
$context = stream_context_create([
'stream' => ['error_mode' => StreamErrorMode::Exception],
]);
try {
$csv = file_get_contents('/data/import.csv', context: $context);
} catch (StreamException $e) {
foreach ($e->getErrors() as $error) {
$logger->error($error->code->name . ': ' . $error->message);
}
}
- StreamErrorMode: Error (Standard, wie bisher), Exception oder Silent
- StreamErrorCode: ein Enum mit Codes wie NotFound oder PermissionDenied, statt Meldungstexte zu vergleichen
- stream_last_errors() und stream_clear_errors(): Fehler ohne Handler auslesen und verwerfen
Das alte Verhalten bleibt der Default. Auf den Default Context lassen sich die neuen Optionen bewusst nicht setzen, damit Bibliotheken nicht plötzlich Exceptions bekommen. Dazu passend: fclose(), file_put_contents() und copy() liefern jetzt false, wenn Flush oder Close scheitern. Alle Details im RFC zu Stream Errors.
Polling API als Basis für asynchrones PHP
Mit Io\Poll\Context bekommt PHP eine native Polling API. Unter Linux arbeitet sie mit epoll, unter macOS mit kqueue, ohne zusätzliche Extension. Im Controller schreibt das niemand. Profitieren werden Event Loops wie ReactPHP, Amp oder Revolt und alles, was darauf aufbaut, etwa WebSocket Server. Als Timeout erwartet wait() ein Time\Duration Objekt. Einen Überblick gibt der RFC zur Polling API.
URI Builder und weitere Neuerungen
PHP 8.5 hat die URI Extension zum Parsen gebracht. PHP 8.6 ergänzt mit Uri\Rfc3986\UriBuilder und Uri\WhatWg\UrlBuilder das Bauen von URLs. Dazu kommen Methoden, die den Typ eines Hosts erkennen, also IPv4, IPv6 oder Domain. Mehr im RFC URI Follow up.
- JSON Fehler mit Position: json_last_error_msg() und JsonException nennen jetzt die Stelle im Payload, an der das Parsen scheitert.
- trim(): Form Feed \f gehört zu den Standardzeichen von trim(), ltrim() und rtrim().
- WeakMap: Referenzen auf Keys, die es noch nicht gibt, funktionieren jetzt.
- pack() und unpack(): < und > als Endianness Modifier für Integer, Float und Double.
- Reflection: ReflectionProperty::isReadable() und isWritable(), ReflectionParameter::getDocComment() und ReflectionAttribute::getShortName().
- mysqli::quote_string(): Quoten und Escapen in einem Aufruf.
- grapheme_strrev(): dreht Strings nach Graphemen um, Emojis bleiben ganz.
- ini_get_all(): liefert mit Details den eingebauten Default jeder Direktive.
- Built in Server: php -S akzeptiert die HTTP Methode QUERY und spiegelt den Host Header nicht mehr.
- OpenSSL: TLS Session Resumption, External PSK und TLS 1.3 Early Data für Streams.
- Sodium: Post Quantum KEMs ML-KEM768 und X-Wing mit libsodium ab 1.0.22, dazu SHAKE und IP Verschlüsselung.
- Curl und Intl: CURLOPT_SEEKFUNCTION für Uploads mit Redirect und IntlNumberRangeFormatter für Spannen wie 3 bis 5 Euro.
- mbstring: Unicode 18.0.
- JIT: läuft jetzt auch auf ZTS Builds unter Apple Silicon.
Was in PHP 8.6 bricht
Lest diesen Teil, bevor ihr Production umstellt. Die vollständige Liste steht in Abschnitt 1 der UPGRADING Datei im PHP Repository.
Sichere Session Defaults
Drei Session Einstellungen haben neue Standardwerte. session.use_strict_mode steht auf 1, session.cookie_httponly auf 1 und session.cookie_samesite auf Lax. Das schützt besser vor Session Fixation und XSS. Es bricht aber Anwendungen, die das Session Cookie per JavaScript lesen oder es bei Cross Site POST Requests erwarten, etwa bei externen Payment Rücksprüngen. Eigene Session Handler brauchen jetzt validateId() und create_sid(). Hintergründe stehen im RFC zu Session Security Defaults.
ValueError statt Warnung
Viele Funktionen werfen jetzt einen ValueError bei Werten, die bisher still falsch durchgingen. Dazu gehören NUL Bytes in Pfaden für file_exists(), is_file(), filesize() oder stat(), ungültige Modi für array_filter(), pathinfo() oder scandir() und zu große Werte für sleep(). Wer bisher Müll übergeben hat, bekommt jetzt eine Exception.
Weitere Brüche
- preg_grep() liefert bei PCRE Fehlern false statt eines halben Arrays.
- trim() entfernt jetzt auch \f am Ende eines Strings.
- SplFileObject verhält sich bei next(), fgets() und current() anders. Wer Dateien zeilenweise liest, sollte Tests laufen lassen.
- base_convert(), bindec(), hexdec() und octdec() melden eine Notice bei Genauigkeitsverlust.
- session_encode() liefert für leere Sessions einen leeren String statt false.
- foreach per Referenz kann nach einer Array Kompaktierung Elemente besuchen, die vorher übersprungen wurden.
Deprecations in PHP 8.6
Deprecations brechen nichts. Euer Code läuft weiter und meldet E_DEPRECATED. Bis PHP 9 solltet ihr sie aber abgearbeitet haben. Die Begründungen sammelt der RFC zu den Deprecations für PHP 8.6.
| Deprecated | Ersatz | Bereich |
|---|---|---|
| is_integer(), is_long() | is_int() | Funktionen |
| is_double(), doubleval() | is_float(), floatval() | Funktionen |
| spl_object_hash() | spl_object_id() | SPL |
| strcoll(), SORT_LOCALE_STRING | Collator aus Intl | Sortierung |
| mb_ereg Funktionen | preg Funktionen | mbstring |
| return in finally | Logik umbauen | Sprache |
| Rückgabewert aus __construct() und __destruct() | kein return Wert | Sprache |
| let und is als Namen | andere Namen | Sprache |
| Dritter Parameter von define() | weglassen | Sprache |
| Objekte an array_walk() und http_build_query() | get_object_vars() | Funktionen |
| mysqli_get_charset(), mysqli_stmt_init() | andere mysqli APIs | MySQLi |
| CSV Methoden von SplFileObject | eigene CSV Logik | SPL |
Prüft besonders spl_object_hash() in euren Abhängigkeiten. Die Funktion steckt in vielen älteren Paketen. Die Wörter let und is sind für künftige Sprachfeatures reserviert, eine Klasse namens Is solltet ihr also umbenennen.
PHP 8.6 Update sicher durchführen
- CI erweitern: einen Job mit dem aktuellen Release Candidate neben eurer Production Version laufen lassen.
- Tools prüfen: Kennen PHPStan, Rector und euer Code Style Tool schon die neue Syntax mit Platzhaltern?
- Deprecations sammeln: E_DEPRECATED im Test Log sichtbar machen und abarbeiten.
- Sessions prüfen: Login, Payment Rücksprung und alles, was das Session Cookie per JavaScript liest.
- Dateizugriffe prüfen: Stellen mit Pfaden aus User Input auf ValueError testen.
- Testen: PHPUnit, Integrationstests und ein Cypress E2E Durchlauf über die wichtigsten Seiten.
Viele Deprecations löst Rector PHP automatisch. Was die aktuelle Version kann, zeigt Rector 2.8 neue Features. Was in PHPUnit gerade neu ist, steht in PHPUnit 13.4 mit Sebastian Bergmann. Wer Symfony nutzt, findet in Symfony 8.2 neue Features erklärt den passenden Framework Stand. Login Flows und Sessions sichert unser Cypress E2E Testing Setup ab, Quality Gates in der Pipeline das NCA CI/CD Pipeline Setup. Wenn Coding Agents das Update vorbereiten, brauchen sie feste Regeln. Die liefern die NCA PHP AI Coding Guidelines.
Fazit
PHP 8.6 macht funktionalen Code endlich angenehm. Partial Function Application und der Pipe Operator passen jetzt zusammen, Duration bringt Typsicherheit für Zeitangaben und Stream Errors räumen mit einer alten Baustelle auf. Gleichzeitig ist das Release strenger. Sichere Session Defaults und viele neue ValueErrors zeigen Fehler, die vorher still durchliefen. Mit Tests, statischer Analyse und einem CI Job auf dem Release Candidate wird das Update planbar.
Häufige Fragen zu PHP 8.6
Was ist 2026 neu in PHP 8.6?
PHP 8.6 bringt Partial Function Application mit ? Platzhaltern, die Klasse Time\Duration, die Funktion clamp(), Readonly Properties mit Defaults, #[\Override] für Konstanten, __debugInfo() auf Enums, Stream Fehler als Exceptions, eine native Polling API, das Enum SortDirection und einen URI Builder. Dazu kommen sichere Session Defaults und viele Deprecations.
Wann erscheint PHP 8.6 im Jahr 2026?
Die finale Version von PHP 8.6 ist laut offiziellem Zeitplan im PHP Wiki für den 19. November 2026 geplant. Davor erscheint am 5. November der letzte Release Candidate. Der Feature Freeze ist vorbei, neue Features kommen nicht mehr hinzu.
Was ist Partial Function Application in PHP 2026?
Partial Function Application ist ein Funktionsaufruf, bei dem ein oder mehrere Argumente durch ? oder … ersetzt werden. PHP führt die Funktion dann nicht aus und liefert eine typisierte Closure, die die fehlenden Argumente erwartet. So ersetzt array_map(round(?, 2), $prices) eine komplette Arrow Function.
Lohnt sich 2026 das Update auf PHP 8.6?
Ja, vor allem für Teams mit viel Callback Code, Pipes oder Zeitlogik. Neue Projekte sollten direkt auf PHP 8.6 starten. Bestehende Anwendungen testen den Release Candidate in der CI und prüfen Sessions, Dateizugriffe und Deprecations, bevor sie Production umstellen.
Was bricht 2026 beim Update auf PHP 8.6?
Am häufigsten treffen Teams die neuen Session Defaults mit Strict Mode, HttpOnly und SameSite Lax. Dazu werfen viele Funktionen jetzt ValueError bei ungültigen Werten, etwa NUL Bytes in Pfaden. preg_grep() liefert bei Fehlern false, trim() entfernt den Form Feed und SplFileObject liest Zeilen anders.
Wofür ist Time Duration in PHP gut?
Time\Duration beschreibt eine Zeitdauer mit fester Einheit und Nanosekunden Genauigkeit. Statt int Parametern, bei denen nur der Name die Einheit verrät, übergebt ihr ein Objekt. Das passt für Timeouts, Cache TTL, Retry Delays und Locks. Die neue Polling API nutzt Duration bereits als Timeout.
Wie funktioniert clamp in PHP 8.6?
clamp($value, $min, $max) liefert den Wert zurück, wenn er zwischen beiden Grenzen liegt. Sonst kommt die nächste Grenze zurück. Die Funktion vergleicht nach normalen PHP Regeln, funktioniert also auch mit Strings und DateTime. Ist min größer als max, wirft PHP einen ValueError.
Welche Funktionen sind in PHP 8.6 deprecated?
Unter anderem is_integer(), is_long(), is_double(), doubleval(), spl_object_hash(), strcoll(), metaphone(), spl_classes() und die mb_ereg Funktionen. Dazu kommen return in finally Blöcken, Rückgabewerte aus Konstruktoren und let oder is als Namen. Der Code läuft weiter, meldet aber E_DEPRECATED.
Funktioniert Partial Function Application mit Konstruktoren?
Nein. Ein Aufruf wie new User(?, ‚admin‘) führt zu einem Compile Fehler. Statische Factory Methoden wie User::create(?, ‚admin‘) funktionieren dagegen, ebenso normale Methoden, Closures und invokable Objekte. Funktionen wie compact() oder extract() lassen sich ebenfalls nicht partiell anwenden.
Ist PHP 8.6 schneller als PHP 8.5?
Bei typischem Code mit Pipes ja. Eine Partial Application mit einem Platzhalter direkt rechts vom Pipe Operator wird zu einem direkten Funktionsaufruf ohne Closure. Dazu kommen Optimierungen im Kern und JIT Support für ZTS Builds auf Apple Silicon. Messt trotzdem mit eurer eigenen Anwendung.
PHP Projekte mit Never Code Alone
Wir bringen eure PHP Anwendungen mit eurem Team auf PHP 8.6: Rector, PHPStan, PHPUnit, Cypress E2E Tests und saubere Pipelines. Kostenloses Kennenlernen, ehrliche Aufwandsschätzung, minutengenaue Abrechnung.
