Hi
On 2026-09-09 10:48, Casper Langemeijer wrote:
It also violates the exception policy in
https://github.com/php/policies/blob/main/coding-standards-and-naming.rst#throwables,
which states:
> If an extension uses external functionality that may throw an exception it
MUST wrap any exception thrown by that functionality into an appropriate exception
of its own. It MUST set the $previous property to the original exception when
doing so.
I've read this last week and this interpretation of the exception
policy has taunted me since then. Tim, I think you are mistaken in your
point of view on this. I'm not aware of any point where exceptions
thrown in user callback methods are wrapped, but at least autoloading,
a very prominent one, does not. https://3v4l.org/vYmts Changing this
(in general for all user callbacks) would be a very inconvenient BC
break for many projects.
Yes, much of the existing standard library predates the policy and more
generally also predates any kind of API *design* regarding exceptions.
The first part of the standard library where the Exception hierarchy got
any real design is the new random API in PHP 8.2 - and that served as
the blueprint for the new URI extension and the exception policy.
Regarding your specific example of autoloading, I'd argue that the
correct behavior for autoloading is to wrap all exceptions. From a user
perspective, autoloading is a blackbox service and it thus should behave
like any other service (e.g. like the session example I have given in a
previous email in this thread). In particular autoloading shows up
“implicitly” in many cases and having a clear indicator that autoloading
is what failed is useful. As an example, when using `class_exists()`, I
don't want arbitrary exceptions to show up: https://3v4l.org/m0DIP#veol
I think this policy should be read differently. I think as a language
user you should not have to be aware of the implementation of a
functions internals. if some function is using something that could
throw an exception this implementation detail should be hidden from the
user. Also because if the function is re-implemented another way this
exception could change. From the perspective of the language user, a
callable provided to a function is not part of the functions internals.
I would agree for functions like `array_map()` or `array_filter()` where
the sole purpose is executing the user callback and which cannot fail
for other reasons. But for `preg_replace_callback()` and similar, the
high level operation is “perform a replacement” and the provided
callback is just an implementation detail. I would find it unexpected
that `preg_replace()` with a broken replacement string (e.g.
hypothetically referencing a group that doesn't exist, this case
currently doesn't seem to emit an error) would throw `PregException`,
but `preg_replace_callback()` with a broken replacement callback would
throw arbitrary errors.
Best regards
Tim Düsterhusp