Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:129326 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 C2A4E1A00EF for ; Thu, 20 Nov 2025 12:03:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1763640221; bh=N3NqM5aPop35U6fZYp4LDeHQ5/S9jjQoErnBR8lm4Hg=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=JltwZC4Cr9QCISD5Jj+wk4X1u6n/PJpSLCcF+4qfnEwy+0x5p7B+9oJXRuf1ZXN6C j6f4xcwUIt490SWPyFs8GoKG1NCWPFhOcanBclfWQIcxiukyG2Rqo5OmmqOx4f9icn LVBv3WYqu7BsBYYmXzMU94YahMJIhM5W1hHQA0s2e+XUHgOXey8y1PtQzj07fBf5GP NT2btg/kCK3PDMy4wx9rEo7iH3YJ9OrmhMtYCNuFwppPLh+9am9R7xvy3HjjB4TpA+ 7EW0GBQwcvQ9Q7nfbUH20xrvjtxi0+CBUOV0Yk+/D7gOi5by1etv+2B9nSDBgHtagt rfrh1gWk1r4fQ== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 9ACEF1806A0 for ; Thu, 20 Nov 2025 12:03:37 +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.8 required=5.0 tests=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-f47.google.com (mail-oo1-f47.google.com [209.85.161.47]) (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 ; Thu, 20 Nov 2025 12:03:25 +0000 (UTC) Received: by mail-oo1-f47.google.com with SMTP id 006d021491bc7-65760bbd866so129650eaf.3 for ; Thu, 20 Nov 2025 04:03:20 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1763640199; x=1764244999; 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=5WdzJelhpfHxhfkVS7T7zkTyt/2Ah+Noa8pIE709Eik=; b=Pa6ncP86sFSj7URn+cgzid7bquZ/asymKTDHaJgjfgeDHlue9fCyukJlPpfKOUMIpu IKgQQlBCxNF2ePBh+iJnbeW78we56JnHFvyGq9psimh54w613omiKHTC4jh3WqPqUVMm TGwheONFWr5kXzxSx3KouYp44cJXsI906Wx+YQyHE32fVguy8oQG2+sEPhYn2ntJlMBV QP2Q1pI00vlYfvSur/g9FNntfqhDHOaGrcfMrWu8/3EdnQfXLSJVxUpr20yubwNnpalz Emrh5eA3h8splLCMM9iI19T+IZBtp/IibJmeDR0Ocyvi9GZJIpXZlV6Axx0WrcS/UB2k FRrg== X-Gm-Message-State: AOJu0YyfLWvBcVSIcMXZaWgfd80jUzRuYZOeZOCWkmNNUalL9yJQc9wN TmG+of2pY3CBGl+qrjXytza+BJxFc2nWHMeSzHca5irFlVK2koh+ENYNvkF5KPWwGSf3N05vtXQ J+Ogd4s3g3I5Y9jK/Sin/u8bo6zJT9tg= X-Gm-Gg: ASbGnctHZh9+caxmx34LsXuUo5j1zklIjrQOed5OAhPjXji27jpWm8Hyi7LMnAd9bV4 u/t14k6k1WUk4wEBgHBGZRJNWw+c0UouKUX0KFfjOSx6bAo2muY8XQ4IqyfJ+U9E6bkYKP+1wwb 3Xzl0no+dJ6a9lN6m+PjBgwTktIBZMElIxv/RORonX+pA68cAWvpkAT/b/JkU1Wb2k+ot/K/W4L Na4faYQ2/UCooAfbk2BJrItPYHDI4qHVueJ2QWsJGTkOAiHthQEz/WNa8k1v/CEBx2CFA== X-Google-Smtp-Source: AGHT+IEoOONlNCTB1W0RNokSs6OJZNjRFCrMiQtgRNwT4yYAeXyEAIZR9bUZrnHniy7/sladN5nJqUj/JmrbzuJjlwk= X-Received: by 2002:a05:6808:1796:b0:450:c6a0:3f39 with SMTP id 5614622812f47-450ff3e8b6amr1483168b6e.58.1763640199336; Thu, 20 Nov 2025 04:03:19 -0800 (PST) Precedence: list list-help: list-unsubscribe: list-post: List-Id: x-ms-reactions: disallow MIME-Version: 1.0 References: In-Reply-To: Date: Thu, 20 Nov 2025 13:03:08 +0100 X-Gm-Features: AWmQ_bmwlM0J6Ma4a6lm-oRWsOj38Koxx1RNHXKp9vf6x-Zw-2kWVMh9VxgXMow Message-ID: Subject: Re: [PHP-DEV] [RFC] Stream Error Handling Improvements To: Bob Weinand Cc: PHP internals list Content-Type: multipart/alternative; boundary="00000000000097eafd0644057bdc" From: bukka@php.net (Jakub Zelenka) --00000000000097eafd0644057bdc Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hi Bob, On Thu, Nov 20, 2025 at 1:11=E2=80=AFAM Bob Weinand w= rote: > Hey Jakub, > On 19.11.2025 23:58:57, Jakub Zelenka wrote: > > On Wed, Nov 19, 2025 at 5:37=E2=80=AFPM Bob Weinand = wrote: > >> On 19.11.2025 12:52:35, Jakub Zelenka wrote: >> >> The code one should be probably named StreamErrorCode (to not interact >> with what Jordi proposed) and think it will need to be backed as there >> should be a straightforward way how to compare it with exception code. I >> might need to extend the gen stub as I'm not sure it allows macro import >> for enum value like for constants or I will need to come up with some >> mapping. I just don't wan to duplicate the numbers. I will figure someth= ing >> out. >> >> How important is it to have exception code? >> > I think the exception code could be quite useful for checking for specifi= c > errors. It's much better than trying to match it by error message which I > saw in past used in normal error handlers. So I can see definitely use ca= se > for that. It might be also possible to group those erors if enums are use= d > so users could just match specific group of errors. > > For the purpose of grouping it would be vastly preferable to add function= s > to the enum class to mark enum values as pertaining to specific groups > "function isIoError(): bool", "function isFileSystemError(): bool" etc. o= r > just simply "function errorGroup(): StreamErrorGroup" which is another en= um > with some grooups like "Io", "Filesystem" etc. rather than comparing rang= es. > > > Yeah that's what I was thinking. Internally I would still probably represent it as num ranges (as it is now) but userspace should use those enum functions. > I found that for our purposes we generally skip the exception code (i.e. >> keep it at zero). >> As a simple example, ErrorException does take two integers - one for >> severity, and one for code, instead of using the severity as code. >> > Severity is almost always warning which I don't think is a good > representation for code. I saw error codes used in various application an= d > I think they are useful. I don't think it hurts to have them. The > implementation of that enum should not be a big problem. I just need to > figure out how to make it nice. > >> I would propose something similar here: call it StreamError and provide = a >> public $error property for the actual enum, rather than squeezing it int= o >> $code. >> > I'm not sure I understand this. The code is a generic identifier for the > error class that can be matched. StreamError would be the actual > representation containing the message and other info - this cannot be > matched in a generic way. > > > My point here is that $code generally does not get used for our > Exceptions. Whenever we need to attach extra information to an exception, > we do it as extraneous properties. (That's what my example with > ErrorException was about.) > > I.e. ignore the existence of $code (just assign zero). > > And add an extra property for the StreamError enum (which now needs no > backing). > > class StreamException extends Exception { > public __construct( > public StreamError $error, > public string $wrapperName, > string $message =3D "", > public string|null $param =3D "", > ?Throwable $previous =3D null > ) { > parent::__construct($message, 0, $previous); > } > } > > Does this make more sense, described as code? > As I see what you mean now. I would prefer to use StreamError name for the class holding all the details including code, wrapper name, message and param as proposed by Jordi because this could be also passed to handler and retrieved from the stored errors. It just seems not right to use StreamException as a container without being thrown (is that done anywhere?) so I think separate class for handler and stored errors (or single last error) seems cleaner. Although StreamException would be then quite similar. I could pass StreamError there as a property but then it would duplicate the message so not sure. In any case I think it's better to call that enum StreamErrorCode. I will still find a clean way to map it to the defines (STREAM_ERROR_CODE_* macros) because that's what I use internally to set code in the error. So not using int value for the exception code won't make that much difference from the implementation PoV. Kind regards, Jakub --00000000000097eafd0644057bdc Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hi Bob,

On Thu, Nov 20, 2025 at = 1:11=E2=80=AFAM Bob Weinand <bobw= ei9@hotmail.com> wrote:
=20

Hey Jakub,

On 19.11.2025 23:58:57, Jakub Zelenka wrote:
On Wed, Nov 19, 2025 at 5:37=E2=80=AFPM Bob Weinand <bobwei9@hotmail.com> wrote:
On 19.11.2025 12:52:35, Jakub Zelenka wrote:
The code one should be probably named StreamErrorCode (to not interact with what Jordi proposed) and think it will need to be backed as there should be a straightforward way how to compare it with exception code. I might need to extend the gen stub as I'm not sure it allows macro import for enum value like for constants or I will need to come up with some mapping. I just don't wan to duplicate the numbers. I will figure something out.

How important is it to have exception code?

I think the exception code could be quite useful for checking for specific errors. It's much better than trying to match it by error message which I saw in past used in normal error handlers. So I can see definitely use case for that. It might be also possible to group those erors if enums are used so users could just match specific group of errors.

For the purpose of grouping it would be vastly preferable to add functions to the enum class to mark enum values as pertaining to specific groups "function isIoError(): bool", "functio= n isFileSystemError(): bool" etc. or just simply "function errorGroup(): StreamErrorGroup" which is another enum with some grooups like "Io", "Filesystem" etc. rather than = comparing ranges.


Yeah that's what I was thinking.= Internally I would still probably represent it as num ranges (as it is now= ) but userspace should use those enum functions.
=C2=A0

I found that for our purposes we generally skip the exception code (i.e. keep it at zero).
As a simple example, ErrorException does take two integers - one for severity, and one for code, instead of using the severity as code.

Severity is almost always warning which I don't think is a good representation for code. I saw error codes used in various application and I think they are useful. I don't think it hurts to have them. The implementation of that enum should not be a big problem. I just need to figure out how to make it nice.

I would propose something similar here: call it StreamError and provide a public $error property for the actual enum, rather than squeezing it into $code.

I'm not sure I understand this. The code is a generic identifier for the error class that can be matched. StreamError would be the actual representation containing the message and other info - this cannot be matched in a generic way.


My point here is that $code generally does not get used for our Exceptions. Whenever we need to attach extra information to an exception, we do it as extraneous properties. (That's what my example with ErrorException was about.)

I.e. ignore the existence of $code (just assign zero).

And add an extra property for the StreamError enum (which now needs no backing).

class StreamException extends Exception {
=C2=A0 =C2=A0 public __construct(
=C2=A0 =C2=A0 =C2=A0 =C2=A0 public StreamError $error,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 public string $wrapperName,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 string $message =3D "",
=C2=A0 =C2=A0 =C2=A0 =C2=A0 public string|null $param =3D ""= ;,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 ?Throwable $previous =3D null
=C2=A0 =C2=A0 ) {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 parent::__construct($message, 0, $previou= s);
=C2=A0 =C2=A0 }
}

Does this make more sense, described as code?

=

As I see what you mean now. I would prefer to use Strea= mError name for the class holding all the details including code, wrapper n= ame, message and param as proposed by Jordi because this could be also pass= ed to handler and retrieved from the stored errors. It just seems not right= to use StreamException as a container without being thrown (is that done a= nywhere?) so I think separate class for handler and stored errors (or singl= e last error) seems cleaner. Although StreamException would be then quite s= imilar. I could pass StreamError there as a property but then it would dupl= icate the message so not sure.

In any case I think= it's better to call that enum StreamErrorCode. I will still find a cle= an way to map it to the defines (STREAM_ERROR_CODE_* macros) because that&#= 39;s what I use internally to set code in the error. So not using int value= for the exception code won't make that much difference from the implem= entation PoV.

Kind regards,

Jakub
--00000000000097eafd0644057bdc--