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
