Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:130205 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 0316A1A00BC for ; Sat, 28 Feb 2026 09:25:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1772270713; bh=Eu5jG/omPEAy8rnka8htJqx0sbda/0/WUADmqcJ21AI=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=Eu8y8LDtSkb1MzLoZFgaQRjQl2ylQIcFhQMvalW7oQpHIfTPiyeyh0MxJY95BdA8A F57Syy+Vuz9ak5V1qVHANkJF6UJ0OlPjnhCFd2fDnyYG70rOoe5Uw/+jLLAvypKR3l efHcWlCLdNEAdm2UeFfDsKB6XSaymexh5zw6sRGoP7kg2bVBF1vPbBsQjnmxrSk46e QBqvGw9isd3DgbjTNOscLnikCeOqfOSMvVvnH5Y6WoPo7HST95PHFu+CnmApKglsGj z1aMM6in01ROAlYEIFmUkIuyuJp0g8ZjwibifAzCs+5Ggqr0UtK86CA+W++fmEh0GV oK0GLUHXNq0Wg== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id CF23C180083 for ; Sat, 28 Feb 2026 09:25:08 +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-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 ; Sat, 28 Feb 2026 09:25:08 +0000 (UTC) Received: by mail-oo1-f47.google.com with SMTP id 006d021491bc7-6774d63d2e0so1198988eaf.1 for ; Sat, 28 Feb 2026 01:25:03 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1772270703; cv=none; d=google.com; s=arc-20240605; b=LT737vFMtJGYlMBNEUYzbZ3887WHXOzG6V6Vxd2W9K47XeIFhEgPyIVewyqd9SdUfs chxNIXBpAToxf0IMK4hailTal5ocAEF/Vm8SRBcSnk8H5kgtgGqgp0VgmWIxRsggevwg wlJeiDMNzX/gsheTfQR+39//S0nnnLLyED4tlXHxWX7CMKq3sLjD3L/1miq4L9d4jb7g 4N4qtHHAZh5N5ZaAr7vwBmc3jB/+vQprICiIZJ7baRBBM9QD/YvX4OSjsfiKKYv7SG/Y 6FF2bEBN1P47P4I2g2fej3t3/oIE6+3+N0Xv9gXBB0yT91PhPozueBQSncz5kcIvJTFH hWLg== 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=Eu5jG/omPEAy8rnka8htJqx0sbda/0/WUADmqcJ21AI=; fh=+Olut09awgBB5IxEO9xPIU68miEei4hvoITNrzLyq5c=; b=LiukHhB7A+IUXWlxv7qY4rA9noPrZxzS7UZAJyGU8nsHjIA9m7jZ82JCkCHml2ZcQE wGpU0/QAqp+RumWNOMlA3CC72t2ZS4uiAZ0lDcmq7Ge9p/ONGe/zsFIBeiObuHCaeWRB Sfxdn+eIhgWMjR1f232YK4jJD3liva9I2HGIx0zGPN/KduFtwlLNONz+lG6miPRhT/kj K6kQN1KUcJvnr0U1mYzUVTEgdH9T+Z1LpFQDMXEZCG6FazsHlBMUGZSNHZUJC+4EvY9c YB01ZcIiQYntrT+cPw3gV7gigezDFv7im68UVjI3mbCw6sYX/DHhHp14PQGY1dBotx9+ +iMw==; 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=20230601; t=1772270703; x=1772875503; 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=Eu5jG/omPEAy8rnka8htJqx0sbda/0/WUADmqcJ21AI=; b=DhD3DeGKrmPVHt7bQudnZjMaKns0OWSK+lOieisgFgVxoEHxaejz38+uSvjKAmwK9R dAcH5v1sXbZu2s1tyLjsljh/xWIv86S3KNzvs0agJ67N9qUcjX7pPLihopRtrmiHc/Ws TgUaPbXZUvqByAvXDovXYnEtEJaLFHJhyMpfmvS1MDcT8shCo3FPJu0dlimnDZ6U3cyg GMxb4t3l+rFSftVICjgBEdCMg9hvm/w+jRts+0EM/NehniSv1Owl2WAF4nVsQ0iYbI7e T/EyByFBGclfPUoac3tAbwt6mHGz5gnOQEXnDpL6gSuoF314nqxPe23+QAMZq9+PNWyj L3lw== X-Gm-Message-State: AOJu0YyIbtq5/sEg3/ltUlgPMOsPpQnyZSWsIFJRmhvtP8BYlrvZQ9VC nhqR/nbYR2QtMOsbgyMQsDC29V+5z8/GLAZ7T3DU4vHJrvkMmA9djS8zTAtOBuUTWlPlkEzKf8I OcJonj8Ye0u/oj1FCtkZcQmxWFFUU5BM= X-Gm-Gg: ATEYQzyco+JTyhzXKTqGTizJqMgf/ztZspjJTWTQkX+f9R9aFAIZahuQVU4HD3rQFlh 9VokYq/epWHSo2lKvGejGlWIf19kI4rcEECs1Iy9aPdqgQDMhoaybZgEppiHdNdmE3Bq0M6gAdm sF/CKr+yAVLWKDGkcdsd9diGW/SFsff14rKGEKnIpmCZwfGaPPRetxohS1ZWvVSzQkn9z8yBKjV zHJ4/VavbX4X5zM3HEOF+DghlmQOK1JWwZU4zmWdoPpyzKZaj/XV0HTseNMU9E7YwuopNcjad2W tbFyZ8A= X-Received: by 2002:a4a:db49:0:b0:67a:6db:2330 with SMTP id 006d021491bc7-67a06db25f7mr167152eaf.14.1772270702543; Sat, 28 Feb 2026 01:25:02 -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: Sat, 28 Feb 2026 10:24:50 +0100 X-Gm-Features: AaiRm526JwW3r0Va47KAL-yxrqwpio87QsXZ7YiNboFpUV-SbpT0yvOIdNoTUE8 Message-ID: Subject: Re: [PHP-DEV] Re: [RFC] Stream Error Handling Improvements To: Nicolas Grekas Cc: PHP internals list Content-Type: multipart/alternative; boundary="000000000000abc869064bdeede6" From: bukka@php.net (Jakub Zelenka) --000000000000abc869064bdeede6 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Fri, Feb 27, 2026 at 11:34=E2=80=AFPM Nicolas Grekas < nicolas.grekas+php@gmail.com> wrote: > > > Le ven. 27 f=C3=A9vr. 2026, 22:21, Jakub Zelenka a =C3=A9= crit : > >> Hi, >> >> On Wed, Feb 25, 2026 at 7:11=E2=80=AFPM Nicolas Grekas < >> nicolas.grekas+php@gmail.com> 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 Soverei= gn >>>>> 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 o= r >>>> 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 a= n >>> 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 =E2=80=94 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 previ= ous >>> error chronologically. Would something like $previous (echoing >>> Throwable::getPrevious()) work better, or is the current naming deliber= ate? >>> >>> >> 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 usef= ul >> one. The follow up errors (if any - most of the time there's just one) a= re >> most of the time not that useful but might add a bit more context so tha= t'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 runtim= e, >>> the set of possible values would depend on which extensions are install= ed, >>> 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 dom= ain >>> 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 hazardou= s >>> >>> The RFC includes an example where stream_context_set_default is used to >>> set error_mode to StreamErrorMode::Exception globally. I'm worried abou= t >>> 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 thr= ow >>> uncaught exceptions, breaking behavior their authors had deliberately >>> chosen. This feels like a significant compatibility hazard for code tha= t >>> 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. >> > > Looks nice thanks! > > I'd just explicitly tell what happens when one tries to change the error > mode globally. An exception? Which one? > > Ok updated it - it's ValueError... Cheers Jakub --000000000000abc869064bdeede6 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
On Fri, Feb 27, 2026 at 11:34=E2=80=AFPM = Nicolas Grekas <nicola= s.grekas+php@gmail.com> wrote:


Le ven. 27 f=C3=A9vr. 2026, 22:21, Jakub Zelenka <<= a href=3D"mailto:bukka@php.net" target=3D"_blank">bukka@php.net> a = =C3=A9crit=C2=A0:
Hi,

On Wed, Feb 25, 2026 at 7:11=E2=80=AFPM Nicolas = Grekas <nicolas.grekas+php@gmail.com> wrote:
Hi= Jakub,

I would like to intr= oduce a new stream error handling RFC that is part of my stream evolution w= ork (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 w= hich addresses the below issues.
=C2=A0
<= blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-l= eft:1px solid rgb(204,204,204);padding-left:1ex">
As there has not been much discussion and= keeping the patch up to date is a slight pain, I plan to open voting on Fr= iday (27/02/26) evening or Saturday (28/02/26) morning unless some changes = are required ofc.

=

The update means that the vote will not ha= ppen in the next two weeks...
=C2=A0
Thanks for the reminder! I discussed this with others and we ra= ised the following points:

1. StreamErrorCode::Non= e: do we need it?

Having an enum case representing "no error&qu= ot; feels a bit off to me. If an API needs to express the absence of an err= or, would,'t StreamErrorCode|null be more idiomatic? StreamErrorCode::N= one seems like a nullable value disguised as an enum case, and it means cal= lers 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 re= moved the enum this is no longer issue. I kept none as constant for compari= ng as it might be useful.
=C2=A0
2. StreamError::$next =E2=80=94 is the naming intentional?

Since st= ream_get_last_error() returns the most recent error and the chain travels b= ackwards through time, $next seems to point to the previous error chronolog= ically. Would something like $previous (echoing Throwable::getPrevious()) w= ork better, or is the current naming deliberate?

<= /blockquote>

I checked this one and realised that $next = is actually better because it's better to keep the first error which fo= r 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 mig= ht add a bit more context so that's why they are chained. I added this = reasoning to the RFC.
=C2=A0
3. Shou= ld StreamErrorCode really be an enum?

The RFC lists in its "Fut= ure Scope" section: "Extension-specific error ranges - Reserved r= anges for extensions to define custom error codes."

This gave u= s pause. Enums in PHP are intentionally a closed, finite type: their value = is precisely that "invalid states become unrepresentable." If ext= ensions can define custom error codes at runtime, the set of possible value= s would depend on which extensions are installed, and the type would no lon= ger be truly enumerable.
Larry touches on this exact tension in this pos= t: when the value space needs to be open or user-extensible, an enum is the= wrong tool.
https://www.ga= rfieldtech.com/blog/on-the-use-of-enums#open-type

I'd also e= xpect 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 fi= xed.

Would a set of integer constants (possibly grouped in a class o= r interface) be appropriate? It would be more honest about the open-ended n= ature of the value space while still allowing meaningful comparisons, witho= ut creating false expectations of exhaustiveness.

=

I changed it to the StreamError class cons= tants and also move the is*Error functions there.
=C2=A0
4. Using stream_context_set_default to change error_m= ode looks hazardous

The RFC includes an example where stream_context= _set_default is used to set error_mode to StreamErrorMode::Exception global= ly. I'm worried about the ecosystem impact here: if any library or appl= ication bootstrap does use this,=C2=A0then existing packages using the comm= on @file_get_contents('maybe_existing_file') idiom could e.g. sudde= nly throw uncaught exceptions, breaking behavior their authors had delibera= tely chosen. This feels like a significant compatibility hazard for code th= at doesn't control its full execution environment.

Would it be w= orth restricting error_mode (and possibly the other new options) so that th= ey can only be set via per-call contexts, not via stream_context_set_defaul= t?


I added that r= estriction 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 pas= ses.=C2=A0

Hope it's ok now! If there's an= ything else, please let me know.

Looks nice thanks!

I'd just explicitly tell what happen= s when one tries to change the error mode globally. An exception? Which one= ?


O= k updated it - it's ValueError...

Cheers
=

Jakub=C2=A0
--000000000000abc869064bdeede6--