PHP 8.6 dovolí u streamů vyměnit varování za výjimky a chybové objekty
Vývojáři PHP vydali 13. srpna první betu verze 8.6. Je v ní návrh, který mění, jak se z funkcí nad streamy dozvíte o chybě: u vlastního kontextu jde místo varování zapnout výjimku nebo tiché ukládání chyb, které se pak vyzvednou jako objekty. Ostrá verze je v plánu na 19. listopadu.

Když v PHP selže fopen(), dozví se o tom program varováním. Kdo varování nechce, napíše před volání zavináč a tím se připraví i o text chyby; kdo ho chce zpracovat, musí si nastavit vlastní obsluhu chyb a lovit z ní řetězec. Vývojový tým PHP oznámil 13. srpna první betu verze 8.6 a je v ní návrh, který tenhle stav mění.
Jmenuje se Stream Error Handling Improvements, napsal ho Jakub Zelenka a schválen byl v poměru 25 hlasů pro, 1 proti a 5 se zdrželo; ke schválení byly potřeba dvě třetiny. Beta je předběžné vydání pro zkoušení a oznámení u ní výslovně varuje, že do ostrého provozu nepatří.
Tři režimy hlášení místo jednoho
Chování se nastavuje volbou error_mode v kontextu streamu a má tři hodnoty. StreamErrorMode::Error je výchozí a chová se jako dosud, tedy varováním nebo poznámkou. StreamErrorMode::Exception vyhodí u ukončující chyby výjimku StreamException. StreamErrorMode::Silent nehlásí nic.
Ukončující chyba je taková, po které operace nemůže doběhnout, typicky nenalezený soubor nebo odepřené oprávnění. Neukončující chyba běh nezastaví, třeba useknutí vyrovnávací paměti. Výjimku dostanete jen u té první skupiny; ta druhá se podle nastavení jen uloží.
$context = stream_context_create([
'stream' => [
'error_mode' => StreamErrorMode::Exception,
]
]);
try {
$stream = fopen('/nonexistent/file.txt', 'r', false, $context);
} catch (StreamException $e) {
echo "Error: " . $e->getMessage() . "\n";
}Chyba je objekt, ne řetězec
Tohle je na celém návrhu to podstatné. Chyba se nepředává jako věta, ale jako instance třídy StreamError, která je final readonly a nese pět vlastností: code s výčtovým typem chyby, message s textem pro člověka, wrapperName se jménem obalu, který chybu vyrobil, severity s úrovní závažnosti podle PHP a terminating s příznakem, jestli šlo o ukončující chybu.
Typ chyby má vlastní výčet StreamErrorCode s položkami jako NotFound, PermissionDenied, ReadFailed, SeekNotSupported nebo CastNotSupported. V souboru s deklaracemi jich je 78; to číslo je náš součet položek toho výčtu v úvodním souboru implementace, sám návrh je nevypisuje.
Uložené chyby se dají vyzvednout později
Druhá volba, error_store, říká, které chyby si má PHP odložit stranou. Hodnoty jsou Auto, None, NonTerminating, Terminating a All. Výchozí Auto se rozhoduje podle režimu hlášení: u varování neukládá nic, u výjimek ukládá neukončující chyby a u tichého režimu všechno.
Odložené chyby vrací nová funkce stream_last_errors() jako pole objektů, seřazené od nejzávažnější. Platí vždy jen poslední operace, která něco odložila, takže mezi voláními není co uklízet; kdo přesto chce úložiště vyprázdnit, má na to stream_clear_errors().
$context = stream_context_create([
'stream' => [
'error_mode' => StreamErrorMode::Silent,
'error_store' => StreamErrorStore::All,
]
]);
$stream = @fopen('http://example.com/nonexistent', 'r', false, $context);
if ($stream === false) {
$first = array_first(stream_last_errors());
if ($first?->code === StreamErrorCode::NotFound) {
echo "Zdroj nenalezen, beru náhradu\n";
}
}Jedna operace umí vyrobit chyb víc
Návrh počítá s tím, že se operace skládá z dílčích kroků a každý může selhat jinak. Když stream_select() volá stream_cast() nad streamem psaným v PHP, vzniknou podle příkladu v návrhu dvě chyby naráz: že obal stream_cast() vůbec neimplementuje a že takový stream nejde vyjádřit jako deskriptor. Obě se vrátí v jednom poli a projdou se běžnými funkcemi nad poli.
K tomu přibyla třetí volba error_handler. Je to funkce zpětného volání s hlavičkou function(array $errors): void a zavolá se bez ohledu na to, jaký režim hlášení je nastavený, takže se hodí na vlastní záznam do logu vedle běžného chování.
Stávající kód se nemá o co rozbít
Výchozí režim zůstává ten dosavadní, takže program, který o nových volbách neví, se chová stejně jako dřív. Nastavit je navíc jde jen na kontextu vyrobeném přes stream_context_create(). Pokus podstrčit je celému procesu přes stream_context_set_default() skončí výjimkou ValueError a návrh k tomu uvádí důvod: knihovny se spoléhají na to, že streamy ve výchozím nastavení varování vydávají.
Drobnosti, které se přece jen mění, návrh vyjmenovává tři. Některé chybně hlášené chyby jsou opravené, kontext se nově předává i podřízeným streamům a hlášení se posouvá blíž k okamžiku, kdy se funkce vrací, takže se pořadí zpráv může proti dnešku prohodit. Čtyři funkce, které dosud kontext přijmout neuměly, dostaly nepovinný parametr navíc: stream_select(), stream_copy_to_stream(), stream_socket_pair() a stream_is_local().
Do listopadu se ještě uvidí
Beta 1 znamená měkké zmrazení novinek, tedy termín, do kterého musí být hlasování o návrzích uzavřená. Plán vydání pak počítá s betou 2 na 27. srpna, tvrdým zmrazením 22. září, prvním kandidátem na vydání 24. září a ostrou verzí 19. listopadu 2026. Stav jednotlivých návrhů vede i nezávislý přehled na PHP.Watch, kde je tenhle veden jako přijatý a naposledy upravený 20. května.
Ve stejné betě je i částečná aplikace funkcí, o které jsme psali u třetí alfy. Rozdíl mezi oběma novinkami je v tom, koho se týkají: otazník místo argumentu je zkratka pro psaní, kdežto nové volby se nastavují vždy na konkrétním kontextu, takže se do kódu samy od sebe nedostanou. Kdo si je chce vyzkoušet, najde v repozitáři deset hotových testů, jejichž jméno začíná na stream_errors_.