Hi, On Wed, Feb 25, 2026 at 7:11 PM Nicolas Grekas <[email protected]> wrote:
> Hi Jakub, > > I would like to introduce a new stream error handling RFC that is part of >>> my stream evolution work (PHP Foundation project funded by Sovereign Tech >>> Fund) : >>> >>> https://wiki.php.net/rfc/stream_errors >>> >>> >> I just updated implementation and RFC to version 2.1 which addresses the below issues. > As there has not been much discussion and keeping the patch up to date is >> a slight pain, I plan to open voting on Friday (27/02/26) evening or >> Saturday (28/02/26) morning unless some changes are required ofc. >> > > The update means that the vote will not happen in the next two weeks... > Thanks for the reminder! I discussed this with others and we raised the > following points: > > 1. StreamErrorCode::None: do we need it? > > Having an enum case representing "no error" feels a bit off to me. If an > API needs to express the absence of an error, would,'t StreamErrorCode|null > be more idiomatic? StreamErrorCode::None seems like a nullable value > disguised as an enum case, and it means callers always have to guard > against it, which somewhat defeats the purpose of using an enum. Am I > missing a use case where ::None is genuinely needed? > As I removed the enum this is no longer issue. I kept none as constant for comparing as it might be useful. > > 2. StreamError::$next — is the naming intentional? > > Since stream_get_last_error() returns the most recent error and the chain > travels backwards through time, $next seems to point to the previous error > chronologically. Would something like $previous (echoing > Throwable::getPrevious()) work better, or is the current naming deliberate? > > I checked this one and realised that $next is actually better because it's better to keep the first error which for streams is really the useful one. The follow up errors (if any - most of the time there's just one) are most of the time not that useful but might add a bit more context so that's why they are chained. I added this reasoning to the RFC. > 3. Should StreamErrorCode really be an enum? > > The RFC lists in its "Future Scope" section: "Extension-specific error > ranges - Reserved ranges for extensions to define custom error codes." > > This gave us pause. Enums in PHP are intentionally a closed, finite type: > their value is precisely that "invalid states become unrepresentable." If > extensions can define custom error codes at runtime, the set of possible > values would depend on which extensions are installed, and the type would > no longer be truly enumerable. > Larry touches on this exact tension in this post: when the value space > needs to be open or user-extensible, an enum is the wrong tool. > https://www.garfieldtech.com/blog/on-the-use-of-enums#open-type > > I'd also expect the built-in list of codes to keep growing over time as > more wrappers and edge cases are covered; which is another hint the domain > may not be fixed. > > Would a set of integer constants (possibly grouped in a class or > interface) be appropriate? It would be more honest about the open-ended > nature of the value space while still allowing meaningful comparisons, > without creating false expectations of exhaustiveness. > > I changed it to the StreamError class constants and also move the is*Error functions there. > 4. Using stream_context_set_default to change error_mode looks hazardous > > The RFC includes an example where stream_context_set_default is used to > set error_mode to StreamErrorMode::Exception globally. I'm worried about > the ecosystem impact here: if any library or application bootstrap does use > this, then existing packages using the common > @file_get_contents('maybe_existing_file') idiom could e.g. suddenly throw > uncaught exceptions, breaking behavior their authors had deliberately > chosen. This feels like a significant compatibility hazard for code that > doesn't control its full execution environment. > > Would it be worth restricting error_mode (and possibly the other new > options) so that they can only be set via per-call contexts, not via > stream_context_set_default? > > I added that restriction and also added context to some stream functions so it can be set explicitly. There will be more function extended in the future if this passes. Hope it's ok now! If there's anything else, please let me know. Cheers Jakub
