> 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 `Throwable`s 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 <[email protected]> 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

Reply via email to