Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:130481 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by lists.php.net (Postfix) with ESMTPS id EB5DB1A00BC for ; Sun, 29 Mar 2026 18:31:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1774809086; bh=XU6fcWVBim/UNU2utuDE+Txyk0CTP0xIo2inN76dzGo=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=ZyIvX2kfrvYPZX2dcLtIM3sIbx91ClqcoSdjlUwdH8IPGD5tCjd+k3ynk6OVMBfXW z4LVruj4l+u2fec3HKj1B9T+F6s9vNV8vTcJNrapOo/7Uc9MQizC8BVQl4U9ClAyoq UcKtBw85D4l+Z10K6ye3HTYG3X1/ZhIhiEcYBfmcciCY9CUPDux9DJJ6xZ9S/m4Jkt xak4S150t8HQjqNt2a2+tzAc4QikDY6YYcHNfDZMa0Zh1ARFuTOuP9A1qvOhNIdzeC Tj/uZ7YVZNk5y+klhN+eIn1lJz3RBLKZuZl4JAvnqguEOQnS3Dr5A2O2z1BdiBcrUr wNnTzKRxDRygA== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 90FA4180077 for ; Sun, 29 Mar 2026 18:31:25 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on php-smtp4.php.net X-Spam-Level: * X-Spam-Status: No, score=1.7 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_50, DMARC_NONE,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,HTML_MESSAGE,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL,SPF_HELO_NONE,SPF_PASS autolearn=no autolearn_force=no version=4.0.1 X-Spam-Virus: No X-Envelope-From: Received: from mail-oo1-f51.google.com (mail-oo1-f51.google.com [209.85.161.51]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Sun, 29 Mar 2026 18:31:25 +0000 (UTC) Received: by mail-oo1-f51.google.com with SMTP id 006d021491bc7-662efd1bdd4so2157959eaf.0 for ; Sun, 29 Mar 2026 11:31:20 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1774809079; cv=none; d=google.com; s=arc-20240605; b=cUt+5dkD5+/R2U+wgtw2K8b3biKoZdBrtqnsqkZG2AgzZQ0y36bzzOn6IE/2R6Soov ZnJ2uxrtQMFmnr2UhPwDqtC86YoAWzSX9mYXSy/7VAJGwiHfpDzUP4GKG89ULKz749wd JZAlMOG50FUOo5qNL8GYk0pOmZqeFlHPJFU4ELKqSOHE7sHYmyJHkF2FtxGC4ct9vJxu X3amGESzTM1etYguUryJN7s0Dcbao0wbeeDBRQVSo9HeGsISbDO3ETrVrXaehyssK9EY xI2srLmo2Hu1yFsSidZU1vl/7Twu5kuUQELinKrarW4WnBdhPS0jEdwe6M3AqGMEMTlF fIAQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version; bh=ERJV7MmUccGWbD3UTBAM7GkTocD5qouTh1uB0JJe7t4=; fh=rdr3p/kyVdJVePevk6jIeW8X/IMH063M4Pe3odJwSo8=; b=V7rp05WfLlvoGYAtfuefuZmO/IHG9XY22SKJGGDQnaLoUz3igQ3vIzKhlSiG5j4rpf QCDWyoSDU8s2eCcoIMTRyVVoRQRGFzabAhCLBUlqR/ezeff9haG3CTFnCoh4sslA90Jq gnZPT3GOd3MNXJYmRiqRD2on93s1cEOWLR883LWzHnJ5WKjsVM4PNB/Y2E+B+UOeBr4P bGVPFVFuYGf27lhQ1ND2KUq8ceTRncPNmBGcTZ/7jyB9VI1P0b6OnG4vqiCwY3PZNzVE +jvFE3gBuz8pnenHnKVIQN2Zx6ewdEY0NEccfLCxd4guOPdfs7JEPME0zuFTIh5+A7iV YBmQ==; darn=lists.php.net ARC-Authentication-Results: i=1; mx.google.com; arc=none X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1774809079; x=1775413879; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=ERJV7MmUccGWbD3UTBAM7GkTocD5qouTh1uB0JJe7t4=; b=BoZxWjSqNaqiXuGifG5r6ROD7cq7Ty1QGdOtCj/m4GkBrspHN7crRKoZbML+AJNZc1 dAZv0q36AyYdrxTNajocFICRkDBc3vt95J8UIKTRKnMt+FyHcj4sP6d00etUyJZ019mU lQu7NRynu2Smi3Hx9jygLV+f/Tr9M1heQWCw52cKCk7TElMQ5++ndwQPuGlzpcEGUYx2 siWjW0YWxp5CXNklhXCWeoE7x6mw4vAn/xcyy9S9qbuTH7Ei8byLFU0jKe1JRs5Y+l6+ cGeeZCao/PbQ7l6jnhLtAIcXA9u0pkRt6svq/gdAE25cXSs4VSqCCn3DKRo8KqMTUqJM n46g== X-Gm-Message-State: AOJu0YzTG+6ui85ma5dKMiVdXAaSUCtX3u5wNX+lX4eac2ETnimHo9+y Um5oyJdpeVPWpo6wB6+Po6aR9zEWr/AppPFw9NRbPrabiw8tbrxSxEGd8IfVt/Iw35X/ie+cPOt 5nAh4MjI9cu0WN8g5CXiLrQvJB0VHqCs= X-Gm-Gg: ATEYQzxBMrt9FnxXT2wJ5nKHu2DPYTn5VCzR8e6K2Bi2ZwHFx08m8bb6pG/eLKHOkBV 7dtZHGDnl6IzUTCuNYKO6yPgaoNmNFMoqlL8e3mETvM4phK9FmpQtu5ijNpyYLuHf+c6gJxpr0a 1iWbBWQtTTk2phR8IotCpQUzZQSjcHV3HCsmVfPDbczvrS6VHJjOd0EJ4+ljM6QrtyKWPsI7f+m lRc+ZH/74FHMZcZA4n+CJDxerxefMecYMTRnI551F3PBrKCq6U2ThhkAO37xyY0bx+AuRV0npKq DxIDrQ== X-Received: by 2002:a05:6820:2902:b0:67e:1e8a:5ecd with SMTP id 006d021491bc7-67e1e8a5fd2mr4672981eaf.31.1774809079512; Sun, 29 Mar 2026 11:31:19 -0700 (PDT) Precedence: list list-help: list-unsubscribe: list-post: List-Id: x-ms-reactions: disallow MIME-Version: 1.0 References: In-Reply-To: Date: Sun, 29 Mar 2026 20:31:07 +0200 X-Gm-Features: AQROBzA9z6nfsq5BHXDRBAfepFmH50wwSy5dZP2khNuKEvX53gqYYbug_m65AEk Message-ID: Subject: Re: [PHP-DEV] [RFC] Stream Error Handling Improvements To: Pierre Joye Cc: PHP internals list Content-Type: multipart/alternative; boundary="000000000000ba807b064e2df085" From: bukka@php.net (Jakub Zelenka) --000000000000ba807b064e2df085 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hi, On Sun, Mar 22, 2026 at 8:26=E2=80=AFPM Jakub Zelenka 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=E2=80=AFPM Pierre Joye = wrote: > >> Hi Jakub, >> >> On Tue, Dec 23, 2025 at 6:10=E2=80=AFAM Jakub Zelenka wr= ote: >> > >> > 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 =3D=3D=3D 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 >> =E2=94=9C StreamIoException >> =E2=94=9C StreamFileSystemException >> =E2=94=9C StreamNetworkException >> =E2=94=9C StreamWrapperException >> =E2=94=94 ... >> >> >> This allows the more natural and idiomatic: >> >> catch (StreamNetworkException $e) { >> // retry =E2=80=94 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 ca= se > 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 --000000000000ba807b064e2df085 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hi,

On Sun, Mar 22, 2026 at 8:26= =E2=80=AFPM Jakub Zelenka <bukka@php.ne= t> wrote:
Hi,

Sorry for slightl= y late reply. I wanted to think about it and was also busy with other stuff= .

On Sun, Mar 1, 2026 at 4:09=E2=80=AFPM Pierre Joye <pierre.php@gmail.com> w= rote:
Hi Jakub,<= br>
On Tue, Dec 23, 2025 at 6:10=E2=80=AFAM Jakub Zelenka <bukka@php.net> 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 Te= ch Fund) :
>
> https://wiki.php.net/rfc/stream_errors

Thank you for this RFC! . It=C2=A0 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) {
=C2=A0 =C2=A0 if ($e->getError()->isNetworkError()) {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 // retry
=C2=A0 =C2=A0 } elseif ($e->getError()->code =3D=3D=3D StreamError::C= ODE_NOT_FOUND) {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 // fallback
=C2=A0 =C2=A0 }
}

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
=E2=94=9C StreamIoException
=E2=94=9C StreamFileSystemException
=E2=94=9C StreamNetworkException
=E2=94=9C StreamWrapperException
=E2=94=94 ...


This allows the more natural and idiomatic:

catch (StreamNetworkException $e) {
=C2=A0 =C2=A0 // retry =E2=80=94 type alone tells you what happened
} catch (StreamNotFoundException $e) {
=C2=A0 =C2=A0 // fallback
} catch (StreamException $e) {
=C2=A0 =C2=A0 // 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<= br> 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 use= rs will care that much if the error is an Io or FileSystem category. It see= ms also slightly messe to have the exception class dependent on the error c= ategory that it holds as a property. I would possibly reconsider it if I sa= w a big use case for categorization but I see it more as a nice to have uti= lity which doesn't need to propagate in this way.
=C2=A0

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 c= ategorised to a single category. This became more obvious with getErrors() = - previously I didn't realised it because it was linked list and someho= w forgot that they can have different categories.

= Kind regards,

Jakub
--000000000000ba807b064e2df085--