Skip to content

Lone namespace separator asks the autoloader for an empty class name #23232

Closed

Description

@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
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 and laravel, 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)

Activity

  1. changed the title [-]is_callable('\::method') asks the autoloader for an empty class name[/-] [+]Lone namespace separator asks the autoloader for an empty class name[/+] on Aug 31, 2026
  2. spawnia commented on Aug 31, 2026

    @spawnia
    ContributorAuthor

    Retitled: is_callable('\::method') is only one entry point. class_exists('\') hits the same zend_lookup_class_ex() path and also autoloads '' — see https://3v4l.org/Qe3u4. Per @Seldaek that is the variant most Composer ClassLoader reports come from.

    #23233 covers both.

  3. added a commit that references this issue on Sep 6, 2026
    3ab8be6
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions