spl_autoload_register

Registers a callback that PHP runs to load a class, interface, trait or enum the first time it is used.

Signature
spl_autoload_register(?callable $callback = null, bool $throw = true, bool $prepend = false): bool
  • Added in PHP 5.1.2

Parameters

ParameterTypeDescription
$callbackoptional?callable= nullThe autoloader to register. It receives the requested name as a single string argument and returns void. If null, the default spl_autoload() implementation is registered.
$throwoptionalbool= trueIgnored as of PHP 8.0.0; a notice is emitted if it is set to false.
$prependoptionalbool= falseIf true, the autoloader is added to the front of the queue instead of the end.

Return value

booltrue on success or false on failure.

Errors

Throws a TypeError as of PHP 8.0.0 when $callback is not a valid callable.

Changelog

  • PHP 8.0.0$callback became nullable, and the $throw parameter is now ignored: a TypeError is always thrown for invalid arguments.

spl_autoload_register() is what removes require statements from the top of every file. When PHP meets a class, interface, trait or enum name it has never seen, it calls each registered autoloader in turn, passing the fully qualified name without a leading backslash, and stops as soon as the name becomes defined.

Your callback's only job is to require the right file. It returns nothing — PHP checks afterwards whether the name now exists. If none of the autoloaders define it, PHP raises a fatal Error.

When to reach for it

  • Any project without Composer that needs PSR-4 style loading.
  • Adding a second loader on top of Composer's — for generated classes, test doubles, or a legacy prefix-to-directory map.
  • Registering a loader with prepend = true so it wins over an existing one, typically to shim or override a vendor class.

What trips people up

Autoloaders must be silent about names they do not own. A loader that unconditionally requires a computed path will fatal on the very first name belonging to another loader — always check the file exists first. This is also what makes class_exists($name) dangerous with a careless autoloader.

Also remember the queue is ordered and cumulative: registering the same closure twice runs it twice, and functions are tried in registration order unless you prepend.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Giving a small Composer-free project PSR-4 loading in a few lines of bootstrap code.
  • Loading generated or cached classes from a build directory alongside Composer's autoloader.
  • Prepending a loader that serves patched copies of a vendor class before the vendor's own file is found.

Frequently asked questions

What is the difference between spl_autoload_register and __autoload?

__autoload() allowed only one loader and was removed in PHP 8. spl_autoload_register() maintains a queue, so several libraries can each register their own loader.

Why does my autoloader cause a fatal error for classes it does not own?

Because it requires a file without checking it exists. Return early for prefixes you do not handle and guard the require with is_file().

Does the autoloader run for interfaces and traits?

Yes. The same queue is used for classes, interfaces, traits and enums, and the callback receives just the name with no indication of which kind was requested.

More examples

Queue order and prepend

The prepended loader runs first, then the original two in registration order. The queue stops as soon as Widget is defined, so class_exists() returns true and nothing after the defining loader is called.

Example · php
<?php
spl_autoload_register(function (string $c): void { echo "first sees $c\n"; });
spl_autoload_register(function (string $c): void {
    echo "second defines $c\n";
    eval("class $c {}");
});
spl_autoload_register(function (string $c): void { echo "prepended sees $c\n"; }, true, true);

var_dump(class_exists('Widget'));
echo count(spl_autoload_functions()), " loaders registered\n";

A PSR-4 style prefix map

The loader claims only the App\ prefix and returns immediately for anything else, which is the behaviour that lets it coexist with other autoloaders. The namespace separators become directory separators, exactly as PSR-4 specifies.

Example · php
<?php
@mkdir('App');
file_put_contents('App/Mailer.php', '<?php namespace App; class Mailer { public const NAME = "mailer"; }');

spl_autoload_register(function (string $class): void {
    if (!str_starts_with($class, 'App\\')) { return; }
    $path = str_replace('\\', '/', substr($class, 4)) . '.php';
    if (is_file('App/' . $path)) { require 'App/' . $path; }
});

echo App\Mailer::NAME, "\n";
unlink('App/Mailer.php'); rmdir('App');

Discussion

  • Be the first to comment on this lesson.