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 >> >> > 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. >
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? 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? 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. 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? Thanks for working on this, we definitely need this! Cheers, Nicolas
