PHP 8.6: Neuerungen, Änderungen und was jetzt zu prüfen ist
PHP 8.6 soll am 19. November 2026 erscheinen. Zu den Neuerungen gehören Partial Function Application, eine Polling-API, die Klasse Time\Duration und Standardwerte für readonly Properties. Wichtiger für bestehende Anwendungen sind die strengeren Session-Defaults und eine lange Liste von Deprecations.
Quelle: Release-Plan und RFCs auf wiki.php.net. Stand 1. November 2026.
STAND
Release-Termin und Entwicklungsstand
Der Release-Plan sieht PHP 8.6.0 für den 19. November 2026 vor. Release Candidate 1 wurde übersprungen, RC2 erschien am 24. September, RC3 am 8. Oktober und RC4 am 21. Oktober. Für den 5. November ist RC5 eingeplant. Plan und einzelne Details der Version können sich bis zum Release noch ändern.
Release Candidates sind für Tests gedacht und gehören nicht auf Produktivsysteme. Anwendungen, Bibliotheken und Erweiterungen lassen sich schon jetzt testen. Freigeben sollte man PHP 8.6 erst nach dem finalen Release und einer eigenen Kompatibilitätsprüfung. Zend erwartet aktive Unterstützung bis Ende 2028 und Sicherheitsunterstützung bis Ende 2030, verbindlich sind die Termine erst mit dem Release.
NEUERUNGEN
Die wichtigsten Neuerungen in PHP 8.6
Partial Function Application
Mit Partial Function Application (PFA) lassen sich Funktionen teilweise vorbelegen. Der Platzhalter ? markiert ein Argument, das später übergeben wird, ... steht für alle restlichen. PHP erzeugt daraus eine Closure. Jedes ? wird dabei zu einem Pflichtparameter der Closure, auch wenn der Parameter der Originalfunktion optional war.
Eigene und eingebaute Funktionen
$makeSlug = str_replace(' ', '-', ?);
echo $makeSlug('Hello World');
// Hello-World
function multiply(int $a, int $b): int
{
return $a * $b;
}
$double = multiply(2, ?);
echo $double(5);
// 10Bei str_replace() sind die ersten beiden Argumente festgelegt, der Platzhalter steht für das Subjekt.
Zusammen mit dem Pipe-Operator
$output = 'Hello World'
|> str_replace(' ', '-', ?)
|> strtolower(...);
echo $output;
// hello-worldDer Pipe-Operator erwartet eine Funktion mit genau einem Argument. PFA liefert sie, ohne dass dafür eine eigene Closure wie fn($v) => str_replace(' ', '-', $v) nötig ist.
PFA ergänzt das bisherige Funktionsmodell und ist vor allem bei Callbacks, Array-Funktionen und Verarbeitungsketten praktisch.
Readonly Properties mit Standardwerten
Instanz-Properties mit readonly dürfen in PHP 8.6 einen Standardwert haben. Bisher war das ein Fehler beim Kompilieren. Das RFC wurde mit 24 zu 0 Stimmen angenommen und ist umgesetzt. Es betrifft normale deklarierte Properties und Properties in readonly-Klassen. Standardwerte an promoted Constructor-Parametern bleiben ganz normale Parameter-Defaults und sind nicht Teil der Änderung.
final class ApiConfig
{
public readonly string $host = 'localhost';
public readonly int $port = 443;
}Der Standardwert gilt als Initialisierung. Die Property ist also schon gesetzt, bevor der Konstruktor läuft, und jede spätere Zuweisung wirft einen Fehler, auch im Konstruktor.
final class ApiConfig
{
public readonly int $port = 443;
public function __construct()
{
$this->port = 8443; // Fehler: bereits initialisiert
}
}Nutzen hat das vor allem bei unveränderlichen Konfigurationsobjekten und bei Klassen, die Interfaces mit { get; }-Properties erfüllen.
Polling-API für I/O
Für I/O-Multiplexing gab es bisher im Wesentlichen stream_select(). Die neue Polling-API im Namespace Io\Poll bietet eine einheitliche Schnittstelle über die Mechanismen des Betriebssystems: epoll unter Linux, kqueue unter BSD und macOS, Event Ports unter Solaris und illumos, WSAPoll unter Windows und poll als Fallback auf anderen POSIX-Systemen. Das Backend wird standardmäßig automatisch gewählt. Das RFC wurde mit 33 zu 1 Stimmen angenommen.
use Io\Poll\Context;
use Io\Poll\Event;
$context = new Context();
$stream = stream_socket_server('tcp://0.0.0.0:8080', $errno, $errstr);
stream_set_blocking($stream, false);
// StreamPollHandle liegt im globalen Namespace
$handle = new StreamPollHandle($stream);
$context->add($handle, [Event::Read], ['type' => 'server']);
while (true) {
$watchers = $context->wait(1); // Timeout in Sekunden
// Ereignisse verarbeiten
}add() gibt ein Watcher-Objekt zurück, wait() liefert die Watcher mit ausgelösten Ereignissen. Welche Timeout-Typen wait() in 8.6 akzeptiert, ist nach den RFC-Texten nicht eindeutig: Das Polling-RFC nennt Sekunden und Mikrosekunden als Integer, das Duration-RFC spricht von einer Duration. Wer die API einsetzt, prüft die Signatur im Manual oder in einer Release Candidate.
Für ReactPHP, Amp und Revolt kann die API eine gemeinsame Grundlage sein, statt dass jede Bibliothek die Betriebssystem-Backends selbst anbindet. Asynchron wird PHP dadurch nicht: Die API ist laut RFC minimal gehalten und bringt weder eine Event-Loop noch eine Async-Laufzeit mit. Timer, Signale, Prozessverwaltung und die Ereignisverarbeitung bleiben Sache der Anwendung oder der Bibliothek. Erweiterungen um Timer-, Signal- und Prozess-Handles liegen als eigenes RFC vor, das für PHP 8.7 vorgesehen ist. Der Hauptgrund für die API liegt in PHP selbst: PHP-FPM, Signalbehandlung in ZTS und weitere interne Komponenten sollen von einer einheitlichen Polling-Infrastruktur profitieren.
Time\Duration
Time\Duration ist eine final readonly Klasse für Zeitspannen mit Nanosekunden-Genauigkeit. Es gibt Factory-Methoden wie fromSeconds(), fromMilliseconds(), fromMinutes() und fromIso8601DurationString(), außerdem add(), sub(), multiplyBy(), divideBy(), negate() und absolute(). Zeitspannen lassen sich mit < und > vergleichen. Das RFC wurde mit 35 zu 1 Stimmen angenommen.
use Time\Duration;
$base = Duration::fromMilliseconds(100);
// Duration ist unveränderlich, add() und multiplyBy() geben neue Objekte zurück
$total = $base->add(Duration::fromSeconds(2));
$attempt = 5;
$delay = $base->multiplyBy(2 ** $attempt);
if ($delay < Duration::fromSeconds(10)) {
// Backoff liegt unter dem Limit
}sleep() und usleep() akzeptieren Duration nicht. Das RFC schlägt keine Änderung bestehender Funktionen vor, die Beispiele dort sind ausdrücklich hypothetisch. Anders als DateTimeImmutable beschreibt Duration eine Zeitspanne und keinen Zeitpunkt oder ein Kalenderintervall.
Reflection: isReadable() und isWritable()
ReflectionProperty bekommt isReadable() und isWritable(). Im RFC-Code heißt die Methode isWritable, nur der URL-Slug des RFC enthält „iswriteable“. Beide Methoden nehmen einen Scope (null für den globalen Scope oder einen Klassennamen) und optional ein Objekt. Das RFC wurde mit 27 zu 0 Stimmen angenommen.
final class Book
{
public private(set) string $title;
}
$property = new ReflectionProperty(Book::class, 'title');
var_dump($property->isReadable(scope: null)); // true
var_dump($property->isWritable(scope: null)); // false, von außen nicht schreibbarNötig wurden die Methoden, weil readonly (PHP 8.1) und asymmetrische Sichtbarkeit (PHP 8.4) die Annahme gebrochen haben, dass isPublic() auch etwas über Schreibbarkeit aussagt. Ohne Objekt wertet PHP nur die statischen Eigenschaften aus. Mit Objekt berücksichtigt es, ob eine readonly Property schon initialisiert ist. Gebraucht werden die Methoden vor allem in ORMs, Serializern, DI-Containern und Frameworks. In normalen Anwendungen fällt die Änderung kaum auf.
DocComments an Funktionsparametern
Dokumentationskommentare dürfen direkt an einzelnen Parametern stehen, vor dem Parameter oder dahinter und vor dem folgenden Komma. ReflectionParameter::getDocComment() liest sie aus. Das RFC wurde mit 23 zu 0 Stimmen angenommen.
function store(
/** @param Book[] */
array $books,
): void {
// ...
}
$parameters = (new ReflectionFunction('store'))->getParameters();
$comment = $parameters[0]->getDocComment();Statische Analyse, IDEs und Codegeneratoren können Typinformationen so gezielt einem Parameter zuordnen, statt sie aus einem gemeinsamen Funktionskommentar herauszulesen.
Kleinere Neuerungen
enum SortDirection
Eine globale Enum mit den Fällen Ascending und Descending als einheitlicher Typ für Sortierrichtungen. Eingebaute Funktionen wie array_multisort() oder scandir() akzeptieren sie noch nicht, Bibliotheken müssen sie selbst auswerten. Das RFC wurde mit 22 zu 2 Stimmen angenommen.
clamp()
clamp(101, 0, 100);
// 100
clamp(-1, 0, 100);
// 0Begrenzt einen Wert auf einen Bereich, auch für Strings und DateTime-Objekte. Ist min größer als max, wirft die Funktion einen ValueError. Eine Eingabevalidierung ersetzt sie nicht.
Enums mit __debugInfo()
Enums dürfen __debugInfo() implementieren und damit steuern, wie var_dump() sie ausgibt. Das hilft bei der Fehlersuche in Domain-Modellen. Zu dieser Änderung liegen nur Übersichtsartikel vor, ein einzelnes RFC wurde nicht geprüft.
Weitere Änderungen
Mehrere Übersichten (Zend, DEV Community) nennen darüber hinaus diese Punkte. Sie sind nicht einzeln gegen RFCs geprüft.
- Die Funktionen
mb_ereg*()undmb_split()sind deprecated und sollen in PHP 9.0 entfallen, weil Oniguruma nicht mehr gepflegt wird. Als Alternative nennt Zend PCRE mit dem Modifier/u. php://filter-Ketten sind standardmäßig auf 16 Filter begrenzt. Das Limit lässt sich anheben.- Rückgabewerte aus
__construct()und__destruct()lösen eine Deprecation aus und sollen in PHP 9.0 zum Fehler werden. mysqli_quote_string()kommt als Gegenstück zuPDO::quote().- TLS-Sessions können über mehrere Requests auf derselben Verbindung wiederverwendet werden.
#[\Override]lässt sich auf Klassenkonstanten anwenden.
SICHERHEIT
Session-Defaults werden strenger
Für bestehende Anwendungen sind die geänderten Session-Defaults die praktisch wichtigste Änderung. Das RFC „Secure Session Configuration Defaults“ wurde angenommen: Jede der drei Einstellungen bekam eine eigene Abstimmung, alle mit mindestens 26 Ja-Stimmen und ohne Gegenstimme.
| Einstellung | Bisher | PHP 8.6 |
|---|---|---|
session.use_strict_mode | 0 | 1 |
session.cookie_httponly | 0 | 1 |
session.cookie_samesite | leer | Lax |
Das RFC ändert die eingebauten Defaults im Quellcode. Ob auch php.ini-development und php.ini-production angepasst werden, nennt es nicht, und eine Übersicht (Laravel News) spricht von „neuen Installationen“. Wer sich auf ein Verhalten verlassen will, setzt die drei Werte deshalb explizit.
session.use_strict_mode
PHP weist ungültige oder nicht akzeptierte Session-IDs zurück, was gegen Session-Fixation hilft. Anwendungen, die Session-IDs bewusst zwischen Subdomains übergeben, können mit dem dateibasierten Handler auf Probleme stoßen: Existiert die Session-Datei auf der empfangenden Seite noch nicht, wird die ID abgelehnt. Die Session sollte auf der Ursprungsseite geschrieben und mit session_write_close() geschlossen werden, bevor die ID weitergegeben wird. Handler, deren validateId() true liefert, sind nicht betroffen. Eigene Handler brauchen korrekte create_sid() und validateId().
session.cookie_httponly
JavaScript kann das Session-Cookie nicht mehr über document.cookie lesen. Anwendungen, die die Session-ID im Browser auslesen und etwa in eigene Header schreiben, müssen angepasst werden. Für Werte, die im Browser gebraucht werden, ist ein separates CSRF- oder Anwendungstoken der richtige Weg.
session.cookie_samesite=Lax
Das Cookie wird bei normalen same-site-Anfragen und bei Top-Level-Navigationen mit sicheren HTTP-Methoden gesendet, bei Cross-Site-POST-Anfragen nicht. Das RFC nennt SP-initiiertes SAML Single Sign-on und ältere Cross-Origin-Formulare als betroffen, dazu kommen externe Login-Prozesse. Wer Cross-Site-POST mit Session-Cookie braucht, muss die Cookie-Einstellungen gezielt setzen, in manchen Fällen mit SameSite=None; Secure, oder auf einen tokenbasierten Ablauf umstellen.
Die Änderung macht bisher implizite Annahmen sichtbar. SSO- und Login-Abläufe sollten deshalb vor dem Upgrade getestet werden.
DEPRECATIONS
Was Entwickler prüfen sollten
Eine Deprecation heißt: Das Verhalten funktioniert noch, PHP gibt aber eine Warnung aus, und es kann in einer späteren Version entfallen. Das RFC „Deprecations for PHP 8.6“ umfasst 35 einzelne Punkte. Nicht alle wurden angenommen: list() und in/out/inout als Bezeichner sind abgelehnt und stehen deshalb nicht in der Liste. Zu einem Teil der angenommenen Punkte stand das Abstimmungsergebnis bei der Prüfung nicht zur Verfügung. Die Liste gibt den RFC-Stand und die Übersichten wieder.
return in finally
Ein return im finally-Block ist deprecated (39 zu 3 Stimmen). Sein Wert überschreibt den Rückgabewert aus try, was überraschend ist und Fehler verdecken kann.
function getConfig(): array
{
try {
return loadConfig();
} finally {
return []; // überschreibt den Rückgabewert aus try
}
}Die übrigen Deprecations im Überblick
| Bereich | Was deprecated wird | Empfehlung |
|---|---|---|
| Bezeichner | let und is als Namen für Klassen, Funktionen und Konstanten (Abstimmungsergebnis für is unbekannt); namespace als Klassenkonstante; Funktion namens readonly (39 zu 1); _ als Konstante oder Compile-Time-Alias | Umbenennen |
| Objekte statt Arrays | array_walk(), array_walk_recursive(), deflate_init(), inflate_init(), mb_convert_variables(), http_build_query() sowie die Stream-Filter zlib.* und bzip2.* mit Objekten | Echte Arrays übergeben |
| Funktions-Aliase | is_double(), is_integer(), is_long(), doubleval() | is_float(), is_int(), floatval() |
| Funktionen | define() mit $case_insensitive; is_a() und is_subclass_of() mit String bei allow_string: false; strcoll(); SORT_LOCALE_STRING; metaphone(); spl_classes(); spl_object_hash() | spl_object_id() statt spl_object_hash(), für spl_classes() Reflection |
| Reflection | ReflectionProperty::setValue() und setRawValue() mit Objekt einer falschen Klasse; ReflectionMethod::invoke() und invokeArgs() mit Objekt bei statischen Methoden | Passendes Objekt, bei statischen Methoden null |
| SPL | Mehrere ArrayIterator-Methoden (getFlags(), setFlags(), asort(), ksort(), uasort(), uksort(), natsort(), natcasesort(), serialize(), unserialize()); die CSV-Methoden von SplFileObject | Auf ArrayObject oder Funktionen ausweichen |
| mysqli und Sessions | mysqli::stmt_init(); mysqli_get_charset() und mysqli::get_charset(); Session-Handler ohne create_sid() und validateId() | $mysqli->prepare(), Handler vervollständigen |
| Konstruktoren | Rückgabewerte aus __construct() und __destruct() (laut Zend Fehler ab PHP 9.0) | Rückgabewert entfernen |
// Statische Methode über Reflection: null statt Objekt übergeben
$method = new ReflectionMethod(Book::class, 'create');
$method->invoke(null);
// Objekt-ID statt spl_object_hash()
$id = spl_object_id($object);
// Prepared Statement direkt erzeugen
$statement = $mysqli->prepare($sql);Die meisten Umstellungen sind mechanisch. Frameworks, CMS-Plugins und ältere Anwendungen betrifft es am ehesten, bei den SPL-, Reflection- und Session-Handler-Punkten lohnt ein gezielter Blick.
HOSTING
Was PHP 8.6 für Hosting-Umgebungen bedeutet
PHP-FPM und paralleler Betrieb
PHP 8.6 braucht eine eigene Runtime mit separaten FPM-Pools, eigenen Sockets oder Ports, passendem CLI-Binary sowie eigenen Konfigurations- und Erweiterungsverzeichnissen. Im Shared Hosting sollte die Version pro Website wählbar sein. Eine globale Umstellung bestehender Websites ist unnötig riskant.
Native Erweiterungen
Imagick, Redis, Memcached, APCu, ionCube Loader, SourceGuardian und eigene PECL-Erweiterungen müssen für 8.6 verfügbar sein. Erweiterungen mit C-Anteilen werden gegen die passende PHP-Version neu gebaut, bei proprietären Modulen ist die Freigabe des Herstellers abzuwarten. Ein erfolgreicher Core-Build sagt nichts darüber, ob alle Erweiterungen laufen.
OPcache und Performance
OPcache gehört in die Testplanung: Speicherbedarf, Cache-Invalidierung, Verhalten nach Updates und FPM-Neustarts sowie Unterschiede zwischen CLI und FPM. Ob eine Anwendung schneller wird, zeigen nur realistische Benchmarks.
Session-Defaults dokumentieren
Kunden sollten wissen, warum sich SSO- oder externe Login-Abläufe nach dem Wechsel anders verhalten können. Einstellungen sind sauber zwischen globaler Konfiguration, FPM-Pools und Website-Konfiguration abzugrenzen.
Beim Rollout lohnt es sich, FPM-Fehler, Worker-Neustarts, Speicherverbrauch, Request-Laufzeiten, Fehler beim Laden von Erweiterungen, Session-Probleme und Deprecation-Meldungen zu überwachen.
Zur Sicherheitslage der aktuellen PHP-Versionen gibt es bei uns zwei Beiträge zu den PHP2Shell-Schwachstellen und den betroffenen Versionen.
KOMPATIBILITÄT
Welche Anwendungen laufen mit PHP 8.6?
Hier gibt es drei Stufen: Eine Anwendung läuft technisch unter PHP 8.6, der Hersteller testet 8.6 regelmäßig, oder der Hersteller gibt 8.6 offiziell frei. Nur die dritte ist eine Kompatibilitätsfreigabe. Bei WordPress, Laravel, Symfony, Nextcloud und anderen großen Projekten gilt das für die konkrete Version, Plugins, Themes, Bundles und Composer-Abhängigkeiten eingeschlossen.
Composer als erste Prüfung
composer validate
composer check-platform-reqs
composer why-not php 8.6Die Befehle zeigen, welche Abhängigkeiten PHP 8.6 nicht zulassen. Ein erfolgreicher Check beweist nicht, dass der Code fehlerfrei läuft, dafür braucht es automatisierte Tests.
Deprecations früh finden
grep -RInE \
'is_double|is_integer|is_long|doubleval|spl_object_hash|spl_classes' \
./src ./appPHP 8.6 gehört in eine separate Testumgebung oder in die CI-Matrix. Die Meldungen sollte man auswerten und nicht unterdrücken. Auch die CSV-Methoden, Reflection-Aufrufe und Session-Handler gezielt prüfen.
VORGEHEN
So gelingt der Umstieg
Sinnvoll ist ein Vorgehen in mehreren Schritten.
Testumgebung
PHP 8.6 in einer Testumgebung installieren und die Anwendung damit starten.
Abhängigkeiten
Composer-Pakete, native Erweiterungen und proprietäre Module kontrollieren.
Deprecations
Neue Warnungen auswerten und die betroffenen Stellen im Code korrigieren.
Sessions und SSO
Sessions, Cookies, SSO und externe Anmeldung gezielt testen, die drei Session-Werte explizit setzen.
Tests und Performance
Unit-, Integrations- und Funktionstests mit 8.6 laufen lassen und Laufzeit sowie Speicherverbrauch mit realistischen Benchmarks vergleichen.
Rollout nach GA
Produktiv erst nach dem finalen Release und einem kontrollierten Rollout.
BEI RDDZ
Wie wir mit PHP 8.6 umgehen
Unser Hosting bietet aktuell PHP ab Version 8.3 an. PHP 8.6 bieten wir erst nach dem finalen Release und eigenen Tests an. Wer vorher wissen möchte, ob die eigene Anwendung betroffen ist, kann sich bei uns melden.
FAZIT
Jetzt testen, danach freigeben
Partial Function Application, Time\Duration, die Polling-API und die Reflection-Erweiterungen betreffen vor allem Frameworks, Bibliotheken und komplexere Anwendungen. Für Hosting-Umgebungen und bestehende Anwendungen zählen die geänderten Session-Defaults und die Deprecations mehr.
Produktiv freigeben sollte man PHP 8.6 nach dem Release am 19. November und einer eigenen Kompatibilitätsprüfung. Bis dahin lohnt sich ein Testlauf mit den Release Candidates.
QUELLEN
Quellen und RFCs
- PHP 8.6 Release Schedule
- RFC: Readonly Property Defaults
- RFC: Polling API
- RFC: Polling API Additions (PHP 8.7)
- RFC: Duration Class
- RFC: isReadable/isWritable reflection methods
- RFC: DocComments for function parameters
- RFC: enum SortDirection
- RFC: Secure Session Configuration Defaults
- RFC: Deprecations for PHP 8.6
- What’s new in PHP 8.6 (Stitcher)
- What’s New in PHP 8.6 (Zend)
- What’s New in PHP 8.6 (Laravel News)
PHP-Update für Ihre Website planen?
Kompatibilität prüfen, Tests aufsetzen, sauber umstellen: Sprechen Sie uns an, wir begleiten Hosting und Betrieb.


