On Sat, Sep 19, 2026, at 8:08 PM, Osama Aldemeery wrote:

> Hi Tim,
>
> I went looking at how some other languages answer this exact question...
> Python, Java and C# each have a counterpart to 
> `preg_replace_callback()`...that is a regex replace that takes a 
> callback and has its own exception to throw.
> And the result across the three languages is unanimous...every one of 
> them lets the callback's exception propagate as-is.
>
> Here is each one:
>  • Python: https://onecompiler.com/python/453rzfyge
>  • C#: https://onecompiler.com/csharp/453rzn4dq
>  • Java: https://onecompiler.com/java/453rwcp43
> This one does not just behave this way...but the docs spell it out as 
> the method's contract 
> <https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/regex/Matcher.html#:~:text=Exceptions%20thrown%20by%20the%20function%20are%20relayed%20to%20the%20caller>:
> "Exceptions thrown by the function are relayed to the caller."
> Now, the other arguments made through this thread plus this one settle 
> it toward not wrapping, then the flag keeps letting a callback's 
> exception propagate and we are done here.
>
> However, if you still read the throwable policy as requiring the wrap, 
> then I believe this is now a question about the policy rather than this 
> RFC, and I would not want the RFC to hinge on this one question, so I 
> scanned the top 4865 packages to see the cost of putting that one 
> question aside, and here are the results:
>  • `preg_replace_callback` + `preg_replace_callback_array`: 2,017 
> occurrences = 4.9% of the eight functions' total (41,413 occurrences)
>  • the other six: 39,396 occurrences = 95.1%
> Anyone can check roughly the same ratio on all of public GitHub with 
> these two searches:
>  • 
> https://github.com/search?q=%28%22preg_replace_callback%28%22+OR+%22preg_replace_callback_array%28%22%29+language%3APHP&type=code
>  • 
> https://github.com/search?q=%28%22preg_match%28%22+OR+%22preg_match_all%28%22+OR+%22preg_replace%28%22+OR+%22preg_filter%28%22+OR+%22preg_split%28%22+OR+%22preg_grep%28%22%29+language%3APHP&type=code
> So if we cannot agree on the callback question, I would rather move the 
> two callback functions to future scope.
> Partly because I do not want to spend more weeks on a point that could 
> end in a rejection either way, and partly because the numbers say the 
> useful case is overwhelmingly the one with no callback in it.
>
> That is, the flag ships on the six functions where none of this arises, 
> the two callback functions reject the flag for now, and whether their 
> version of it wraps or propagates gets settled with the room it needs 
> in its own follow-up after this RFC (if it passes).
>
> Regards,
> Osama

When to wrap an exception is a tricky question overall, and one that user-space 
struggles with a fair bit, too.

For me, the key deciding question is whether the error indicates a failure of 
the implementation details (eg, wrapping a DB error vs wrapping a Redis error) 
or a failure of the input.  Implementation details not relevant to the caller 
should get wrapped into a more locally-meaningful exception, as the current 
policy states.

However, I believe Python, C#, and Java are correct in this case: The callback 
is an input.  It's not an implementation detail hidden from the caller, it's 
explicitly provided by the caller. Thus if that fails, the caller does care if 
it's a DB error or Redis error or whatever.  That's in contrast to, say, an 
invalid regex string, which is an error in the regex system itself, and thus a 
Preg exception/error is entirely reasonable.

If the standing policy isn't nuanced enough to handle that, then the standing 
policy should be updated.

--Larry Garfield

Reply via email to