Re: [RFC] [VOTE] PREG_THROW_ON_ERROR
| From: | Robert Humphries | Date: | Mon, 07 Sep 2026 13:04:49 +0000 |
| Subject: | Re: [RFC] [VOTE] PREG_THROW_ON_ERROR | ||
| References: | 1 2 3 4 5 6 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-132443@lists.php.net to get a copy of this message | ||
> I think there might be a misunderstanding based on how you phrased that
> paragraph. To provide a more specific example:
Sorry - I think I might have just worded my message poorly, as your
more detailed example is how I understood the
RandomException to
look like. I think the core is that in both cases; but specifically
with the session example, the action is what has failed (and
regardless of cause then it is desired to have a single catch to
handle that).
> preg_replace_callback() is different in that I explicitly pass in a
> callback and thus I'm technically in full control over the code that is
> being executed and I can theoretically know what exceptions could
> possibly be thrown and might intentionally want to handle them
> explicitly
Looking at this from a different angle - the first part (in that the
developer is in full control of the code) might be the most important
part here. If the developer wants any failure (a non-zero
preg_last_error() result or an error that occurs during the
callback) to have a single catch block then the developer is able to
throw a PregException themselves (or a child of PregException).
However if PregException wraps any Throwables in the userland
callbacks, a developer who wants to have multiple catch blocks (or
throw some exceptions that propagate to a higher scope in their
callback) can only do that by catching and rethrowing.
On Mon, Sep 7, 2026 at 1:31 PM Tim Düsterhus <tim@bastelstu.be> wrote:
>
> Hi
>
> On 2026-09-07 13:58, Robert Humphries wrote:
> >> Arguably this specific case is a bit debatable, but as the author of
> >> the
> >> throwable policy RFC, I believe that it is at least violated in
> >> spirit.
> >> The goal of the throwable policy generally, and also with regard to
> >> that
> >> specific paragraph is to allow reliably handling groups of errors
> >> without needing to wrap every individual statement into its own
> >> try-catch block.
> >
> > Obviously you wrote the policy and so are best placed to interpret it
> > (and I am not a core developer / person with voting rights); however I
> > agree with the angle Osama is coming from here - I wouldn't say this
> > is an error that is (always) part of the same group. There wasn't any
> > error in the call to preg_replace_callback itself (or any
> > of its
> > functionality) - the error was in a way during the processing of the
>
> Yes, I agree that this case is not entirely clear-cut - and it's good
> we're having this discussion now.
>
> > If I have understood the other example correctly, this contradicts
> > quite significantly with the CSPRNG throwing an Exception that
> > RandomException contains - as the failure is a core issue
> > within the
> > function call itself as opposed to logic that occurs in userland.
>
> I think there might be a misunderstanding based on how you phrased that
> paragraph. To provide a more specific example:
>
> Consider I have a session implementation that uses Redis as its session
> storage backend. Session IDs need to be created using secure randomness,
> i.e. using the CSPRNG. Both the Redis backend and the CSPRNG can
> theoretically fail. As a user when create a new session I want to be
> able to just catch (SessionInitializedFailedException) and not care
> about whether the CSPRNG or the Redis connection failed, and I might not
> even know if it's Redis, Memcache, a File System or a MySQL database.
> Thus any underlying issues must be wrapped into a session-specific
> exception.
>
> preg_replace_callback() is different in that I explicitly pass in a
> callback and thus I'm technically in full control over the code that is
> being executed and I can theoretically know what exceptions could
> possibly be thrown and might intentionally want to handle them
> explicitly. On the other hand, failing to execute the callback means
> that the replacing operation failed, no further callbacks will be called
> and preg_replace_callback() will not return anything - and that is a
> “running this regex failed” a.k.a. PregException situation to me.
>
> > If anything, I would argue that under the policy this should go the
> > other way and become PregError:
> >> The Error hierarchy MUST NOT be used for errors that are expected to
> >> be thrown (and caught) during normal operation of a PHP program.
> > In terms of the possible errors that could occur, I would expect at
> > least PREG_INTERNAL_ERROR,
> > PREG_BAD_UTF8_ERROR &
> > PREG_JIT_STACKLIMIT_ERROR to be code errors that require a
> > developer
> > to need to correct their code (as my understanding of these would be
> > that the pattern is invalid, or not quoted correctly, etc. Although
> > PREG_BACKTRACK_LIMIT_ERROR &
> > PREG_RECURSION_LIMIT_ERROR are more
> > likely to occur based on user input, then the limit for both is
> > controlled by an ini setting - so again, this likely isn't something I
> > would say is expected to be thrown and caught during normal operation
> > of a PHP program. The final error
> > (PREG_BAD_UTF8_OFFSET_ERROR) I
> > _think_ would still likely need a code change to fix it occurring -
> > although I have only done a quick Google to see _when_ it may occur.
>
> This is a good point. I agree that things like pattern compilation
> failures should be a PregError, since this is a clear programmer error
> and regular expressions are not supposed to be untrusted inputs. For the
> error error situations I would need to check as well if they are
> expected during regular operation or not. The backtrack or recursion
> limits I can see being caught intentionally to provide better error
> messages to a user (thus PregException).
>
> Best regards
> Tim Düsterhus