skip to content

In PHP, what does spl_autoload_register() do, and what happens when code uses a class that is not yet defined?

level: juniorimportance: must knowfreq 72%

answer

  1. a last chance before class not found
  2. callbacks receive the fully qualified name
  3. tried in order until the class exists
  4. no autoloader succeeds: Error thrown
  5. __autoload() removed in PHP 8.0

basics

~20 s

spl_autoload_register() adds a callback to PHP's autoloader queue. When code uses an undefined class, PHP calls each callback in order with the class name until one defines the class; if none does, an Error "Class not found" is thrown.

solid answer

~50 s

**Autoloading** lets PHP load a class file on demand instead of requiring every file up front. `spl_autoload_register($callback)` appends a callable to a per-request queue. When running code needs a class, interface, trait or enum that is not defined yet, for example through `new`, a static call or `class_exists()`, the engine calls each registered callback in order, passing the **fully qualified class name** without a leading backslash. A callback typically maps the name to a file path and `require`s it. As soon as the class exists after a callback returns, PHP stops and continues the original operation; if every callback runs and the class still does not exist, PHP throws `Error: Class "App\Foo" not found`. The old global `__autoload()` function, deprecated in 7.2, was removed in PHP 8.0; `spl_autoload_register()` is the only mechanism, and Composer's generated autoloader registers itself through it.

code

php · 14 lines
php
<?php
declare(strict_types=1);

spl_autoload_register(static function (string $class): void {
    echo "autoload: {$class}\n";
});

var_dump(class_exists('Shop\Cart'));   // autoload: Shop\Cart, then bool(false)

try {
    new Shop\Cart();                   // autoload: Shop\Cart
} catch (\Error $e) {
    echo $e->getMessage(), "\n";       // Class "Shop\Cart" not found
}

go deeper

for a junior

Know that spl_autoload_register() registers a callback that loads a class file the first time the class is used, and that Composer's autoloader works this way.

for a middle

Walk through the queue: callbacks run in order with the fully qualified name until the class exists, and a missing class ends in Error for new but false for class_exists().

for a senior

Debug missing classes by inspecting spl_autoload_functions() and the exact name the callbacks receive, and remember that functions are never autoloaded.

for a principal

Keep one autoloading strategy per application, generated where possible, so class loading stays predictable across entry points and deployments.

## The problem autoloading solves Before autoloading, every script began with a list of `require_once` lines, one per class it might use. The list had to be kept in sync by hand, loaded classes the request never touched, and broke whenever files moved. **Autoloading** inverts this: PHP asks your code to load a class at the moment it is first needed. ## How spl_autoload_register works `spl_autoload_register()` has the signature `spl_autoload_register(?callable $callback = null, bool $throw = true, bool $prepend = false): bool` and adds `$callback` to an internal, per-request **queue of autoloaders**. The callback receives one argument, the class name, and is expected to make the class exist, usually by requiring a file: ```php <?php declare(strict_types=1); spl_autoload_register(static function (string $class): void { $file = __DIR__ . '/src/' . str_replace('\\', '/', $class) . '.php'; if (is_file($file)) { require $file; } }); $invoice = new App\Billing\Invoice(); // triggers the callback with "App\Billing\Invoice" ``` When the engine needs an undefined class-like symbol (class, interface, trait or enum), it: 1. Takes the name **as written after namespace resolution**, strips any leading backslash and passes it to the first autoloader. 2. After the callback returns, checks whether the class now exists. If it does, it stops and resumes the original operation. 3. Otherwise it calls the next autoloader in the queue. 4. If the queue is exhausted, the operation fails: `new` or a static call throws `Error` with `Class "App\Billing\Invoice" not found`, while `class_exists()` simply returns `false`. The callback's return value is ignored; only whether the class exists afterwards matters. Registering the same callback twice is a no-op. ## A timeline of one lookup For `$cart = new Shop\Cart();` with two registered autoloaders, a host loader and a plugin loader: - The engine finds no `shop\cart` in its class table. - It calls the host loader with `"Shop\Cart"`. The loader maps it to a path, finds no file and returns. - It calls the plugin loader with the same name. That loader requires `plugins/shop/src/Cart.php`, which declares the class. - The engine sees the class now exists, skips any remaining loaders and finishes the `new` expression. - The next `new Shop\Cart()` in the same request finds the class immediately; no autoloader runs again. ## What it is not - It is **not** triggered for functions or constants. PHP has no function autoloading; files of functions must be required explicitly. - It does **not** make a class available ahead of time. The file is loaded at first use, so a class declared in an unrelated file is found only if some autoloader knows where to look. - It is **not** tied to any file layout. The callback decides the mapping; PSR-4 is a convention for that mapping, not something PHP enforces. ## The removal of __autoload() Early PHP 5 used a single global function named `__autoload($class)`. Because only one such function could exist, two libraries could not both install one. The SPL extension's `spl_autoload_register()` replaced it with a queue of callbacks, PHP 7.2 deprecated `__autoload()`, and **PHP 8.0 removed it**: declaring a function with that name no longer registers anything. Code that still has one must move its body into a callback passed to `spl_autoload_register()`. | Mechanism | Several autoloaders | Status in PHP 8.5 | |---|---|---| | `__autoload()` function | no, only one | removed in 8.0 | | `spl_autoload_register()` | yes, a queue | current | ## Related functions - `spl_autoload_unregister($callback)` removes a callback from the queue. - `spl_autoload_functions()` returns the registered callbacks in order, which helps when debugging. - `spl_autoload_call($class)` runs the queue manually for a name. - Calling `spl_autoload_register()` with no callback registers PHP's built-in `spl_autoload()`, which lowercases the class name and looks for a file with one of the extensions from `spl_autoload_extensions()` (by default `.inc,.php`) on the include path. It is rarely used in modern code. ## In a modern project Most projects never write an autoloader: Composer generates `vendor/autoload.php`, and requiring that one file registers Composer's class loader with `spl_autoload_register()`. The engine behaviour above is still what runs underneath, which is why knowing it helps when a class unexpectedly cannot be found.

  • In PHP, does the autoloader run when a namespaced function such as App\helpers\slug() is undefined?
    No. Autoloading covers class-like symbols only: classes, interfaces, traits and enums. A call to an undefined function throws `Error: Call to undefined function` without consulting any autoloader. Files of functions must be loaded explicitly, typically with `require` in a bootstrap file.
  • In PHP, what name does an autoloader receive for new \App\Model\User() inside another namespace?
    `App\Model\User`: the fully qualified name after the file's namespace and imports were applied, without a leading backslash, and in the letter case written in the code. The autoloader never sees the short or aliased name the source used.
  • In PHP, what does spl_autoload_register() with no arguments do?
    It registers PHP's built-in `spl_autoload()` as an autoloader. That implementation lowercases the class name, turns namespace separators into directory separators and tries each extension from `spl_autoload_extensions()`, `.inc,.php` by default, along the include path. Its lowercasing makes it a poor fit for PSR-4 layouts.

saying these in an interview costs you the question

  • Autoloading loads every class file at the start of the request
  • Defining a function named __autoload still registers an autoloader in PHP 8
  • Autoloading also loads undefined functions and constants
  • Only one autoloader can be registered per request
  • The autoloader's return value tells PHP whether the class was loaded