Hi, On Sun, Mar 22, 2026 at 8:26 PM Jakub Zelenka <[email protected]> wrote:
> Hi, > > Sorry for slightly late reply. I wanted to think about it and was also > busy with other stuff. > > On Sun, Mar 1, 2026 at 4:09 PM Pierre Joye <[email protected]> wrote: > >> Hi Jakub, >> >> On Tue, Dec 23, 2025 at 6:10 AM Jakub Zelenka <[email protected]> wrote: >> > >> > Hello, >> > >> > 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 >> >> Thank you for this RFC! . It is clearly needed and the error chaining >> design is great. There are a few points I'd like to raise, the last >> two being slightly off topic specifically to that rfc but however very >> related to. So a slightly long reply. >> >> 1. New exceptions >> >> The current design has a single flat StreamException. This means the >> exception path requires inspecting the error object to branch on >> category: >> >> catch (StreamException $e) { >> if ($e->getError()->isNetworkError()) { >> // retry >> } elseif ($e->getError()->code === StreamError::CODE_NOT_FOUND) { >> // fallback >> } >> } >> >> The current design introduces StreamException, which is good. But as a >> single flat class it doesn't actually allow to use exceptions the way >> exceptions are meant to be used. One still has to inspect the error >> object inside the catch block to know what happened. It introduces the >> syntax of exception handling without the benefit of it. >> >> Since the error categories are already well-defined and stable in this >> RFC, StreamException could be a base class with typed subclasses >> mirroring those categories: >> >> StreamException >> ├ StreamIoException >> ├ StreamFileSystemException >> ├ StreamNetworkException >> ├ StreamWrapperException >> └ ... >> >> >> This allows the more natural and idiomatic: >> >> catch (StreamNetworkException $e) { >> // retry — type alone tells you what happened >> } catch (StreamNotFoundException $e) { >> // fallback >> } catch (StreamException $e) { >> // generic >> } >> >> The StreamError value object can stay as in the RFC (and keep "BC" for >> the error const's bag), it's appropriate for the inspection/silent >> mode use case. I see the typed exception hierarchy and the flat value >> object serve different purposes and complement each other: >> $e->getError() still gives you full detail when you need it. These are >> separable concerns currently merged into one class. >> > > I thought about this a lot and I'm not sure this would be that useful as I > don't see a big enough use case for cetegorization on exception level. It > was exposed more as a nice to have but I doubt that users will care that > much if the error is an Io or FileSystem category. It seems also slightly > messe to have the exception class dependent on the error category that it > holds as a property. I would possibly reconsider it if I saw a big use case > for categorization but I see it more as a nice to have utility which > doesn't need to propagate in this way. > > When implementing the recent changes I actually realised that introducing this exception hierarchy does not make any sense because there can be multiple errors in an exception and they can have different categories so the exception cannot be reasonably categorised to a single category. This became more obvious with getErrors() - previously I didn't realised it because it was linked list and somehow forgot that they can have different categories. Kind regards, Jakub
