> 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
