[php-src] Issue #23232: is_callable('\::method') asks the autoloader for an empty class name
[email protected] (spawnia)
| Newsgroups | php.bugs |
|---|---|
| Message-ID | <[email protected]> |
Issue: https://github.com/php/php-src/issues/23232
Author: spawnia
### Description
`is_callable()` on a string of the form `'\::method'` asks the autoloader for the **empty class name**. The same string without the leading backslash, `'::method'`, does not autoload at all. A leading `\` only marks the name as fully qualified, so this asymmetry looks like a bug.
The following code:
```php
<?php
spl_autoload_register(function (string $class): void {
echo "autoload: '$class'\n";
});
foreach (['::a', '\::a', '\Foo::a', 'Foo::a'] as $callable) {
echo "is_callable(\"$callable\")\n";
is_callable($callable);
}
```
Resulted in this output:
```
is_callable("::a")
is_callable("\::a")
autoload: ''
is_callable("\Foo::a")
autoload: 'Foo'
is_callable("Foo::a")
autoload: 'Foo'
```
But I expected this output instead:
```
is_callable("::a")
is_callable("\::a")
is_callable("\Foo::a")
autoload: 'Foo'
is_callable("Foo::a")
autoload: 'Foo'
```
Reproduced unchanged on 8.3.32, 8.4.24 and 8.5.9 (official `php:*-cli` images).
An empty class name can never resolve, so autoloading it is pure overhead — and it is observable overhead. Composer's `ClassLoader::findFileWithExtension()` does `$first = $class[0];`, which on `''` emits `Warning: Uninitialized string offset 0`. Any application that promotes warnings to exceptions (Laravel's `HandleExceptions`, for example) then fails.
We hit this in CI: Laravel's `Factory::expandAttributes()` calls `is_callable()` on every string attribute, and a randomly generated password starting with `\::` (about 1 in a million with Faker's `password()`) made unrelated tests error out with `ErrorException: Uninitialized string offset 0`. Fixes are also filed with [composer](https://github.com/composer/composer/pull/13031) and [laravel](https://github.com/laravel/framework/pull/61151), but the autoload request for `''` looks wrong regardless of who else guards against it.
I am happy to prepare a patch rejecting the empty class name before autoload if you agree this should change.
### PHP Version
```
PHP 8.3.32, 8.4.24, 8.5.9
```
### Operating System
Linux (official `php:8.3-cli`, `php:8.4-cli`, `php:8.5-cli` images)