# Namespaces and Autoloading (PSR-4)

> PHP namespaces and autoloading with PSR-4: from class name to file path, spl_autoload_register, the Composer autoloader and checks after an incident.

Source: https://phpsos.de/en/php/namespaces-autoloading/  
As of: 25/10/2026  
Provider: PHP SOS, PHP emergency help and server security. Immediate help via WhatsApp: https://wa.me/491736494914?text=Hello%20PHP%20SOS%2C%20we%20need%20help%20with%20our%20PHP%20server.%20Company%3A%20%E2%80%A6%20Website%3A%20%E2%80%A6

**In short:** In PHP, namespaces are something like folders for class names: `App\Rechnung\Pdf` and `Bibliothek\Pdf` can exist side by side without interfering. Autoloading ensures that PHP loads a class only when it is needed for the first time. The PSR-4 standard defines how a class name becomes a file path; Composer then generates the matching autoloader. Because this autoloader runs on every request, it is among the first things to be checked after a security incident.

## Why PHP needs namespaces

Namespaces have existed since PHP 5.3.0. Before that, all classes and functions shared a single global namespace. If two libraries were both called `Logger`, things crashed. Developers helped themselves with long names such as `Firma_Modul_Unterbereich_Logger`.

The PHP manual names two problems that namespaces solve: name collisions between your own code, PHP-internal classes and third-party libraries, and overlong names that arose only to work around those collisions. For decision-makers this means: only namespaces made it practical to combine dozens of third-party packages in one project, as is common today with [Composer](https://phpsos.de/en/php/composer/).

## Namespaces in practice: namespace, use, aliases

A file declares its namespace in its first statement. With `use`, you pull classes in from other namespaces, under a shorter name if you wish.

```php
<?php
declare(strict_types=1);

namespace App\Rechnung;

use App\Kunde\Kunde;
use Psr\Log\LoggerInterface as Log;

final class PdfErzeuger
{
    public function __construct(private Log $log) {}

    public function erzeugen(Kunde $kunde): string
    {
        $this->log->info('PDF erzeugt', ['kunde' => $kunde->id]);
        return \sprintf('Rechnung für %s', $kunde->name);
    }
}
```

The full name of this class is `App\Rechnung\PdfErzeuger`. The leading backslash in `\sprintf` explicitly refers to the global PHP function.

## Autoloading: loading classes on demand

Without autoloading, every script would have to include all required files with `require`. With `spl_autoload_register()`, you instead register a function that PHP calls as soon as an unknown class, interface, trait or enum is used. It receives the class name and loads the matching file.

```php
<?php
spl_autoload_register(function (string $klasse): void {
    $praefix = 'App\\';
    $basis   = __DIR__ . '/src/';

    if (!str_starts_with($klasse, $praefix)) {
        return; // not responsible, the next autoloader's turn
    }
    $datei = $basis . str_replace('\\', '/', substr($klasse, strlen($praefix))) . '.php';
    if (is_file($datei)) {
        require $datei;
    }
});
```

`spl_autoload_register()` can be called several times. PHP then asks the registered autoloaders one after another until one has loaded the class. In practice, large applications often have several: the Composer autoloader for libraries, one of the CMS itself and others from plugins or modules. For admins this means: which code is actually loaded during a request results from the interplay of all these autoloaders and not from the folder structure alone.

The manual strongly advises against throwing exceptions in an autoloader; PSR-4 explicitly forbids it. The older function `__autoload()` was deprecated in PHP 7.2.0 and removed in PHP 8.0.0.

## PSR-4: from class name to file path

PSR-4 is a PHP-FIG standard. A fully qualified class name begins with a vendor namespace. A prefix of the namespace is assigned to a base directory, the rest of the name yields subfolders, and the file ends in `.php`. Upper and lower case must match exactly. This is what the mapping looks like in `composer.json`:

```json
{
    "autoload": {
        "psr-4": { "App\\": "src/" }
    }
}
```

| Class name | File |
|---|---|
| `App\Kunde\Kunde` | `src/Kunde/Kunde.php` |
| `App\Rechnung\PdfErzeuger` | `src/Rechnung/PdfErzeuger.php` |
| `App\Rechnung\Pdf\Vorlage` | `src/Rechnung/Pdf/Vorlage.php` |

A classic stumbling block is letter case. On development machines running Windows or macOS, the file system often does not distinguish between `Kunde.php` and `kunde.php`, but on a Linux server it does. An application that runs locally then fails to find a class on the server. The PSR-4 rule to use names in exactly the right spelling prevents such surprises at deployment.

Besides `psr-4`, Composer offers `classmap` for code without a standard structure and `files` for files that are loaded on every request, such as helper functions. Further PHP-FIG standards are described on the page [PSR standards](https://phpsos.de/en/php/psr-standards/).

## Optimising the autoloader in production

In production, the autoloader should ideally no longer search the file system but look things up in a ready-made list. Composer offers two levels for this:

1. `composer install --no-dev --optimize-autoloader` converts the PSR-4 rules into a class list. According to the Composer documentation, this is recommended for production.
2. `--classmap-authoritative` goes further: classes are loaded exclusively from the list. The autoloader then does not load files that are not listed at all.
3. With every deployment the list is regenerated so that new classes are found.

## Autoloading and security after PHP2Shell

PHP2Shell affects the PHP interpreter, not the autoloader. The update to PHP 8.5.12, 8.4.27, 8.3.36 or 8.2.35 and the restart of all workers remain mandatory. After a possible incident, however, the autoloader deserves particular attention: `vendor/autoload.php` and all files listed under `files` are executed on every request. A line injected there therefore takes effect across the whole website, without a conspicuous new file sitting in the upload folder.

Check, therefore, whether `vendor` and the autoload files match the verified state from version control. The articles [Finding recently changed files](https://phpsos.de/en/blog/geaenderte-dateien-finden/) and [Comparing CMS core files with the original](https://phpsos.de/en/blog/cms-kerndateien-vergleichen/) are helpful. When in doubt, a freshly generated `vendor` from the lock file is safer than any individual repair.

## How does PHP SOS help?

- We compare `vendor`, the autoloader and entry files with the verified state and flag every deviation.
- We restore the package set from the lock file and set up an optimised autoloader.
- We check whether only the public folder sits in the web root and source code is not directly reachable via URL.
- In case of infection, we carry out the cleanup as part of [malware removal](https://phpsos.de/en/leistungen/malware-entfernung/) and document the result.


## Frequently asked questions

**Since when have there been namespaces in PHP?**  
Since PHP 5.3.0. According to the manual, they solve two problems: name collisions between your own code, PHP and third-party libraries, and overlong class names that arose only to avoid such collisions.

**What is the difference between PSR-0 and PSR-4?**  
Both map class names to file paths. With PSR-4, the namespace prefix is not repeated in the file path, which results in flatter directories. PSR-0 is classified as deprecated by the PHP-FIG; PSR-4 is the recommended standard.

**Does __autoload() still work?**  
No. __autoload() was deprecated in PHP 7.2.0 and removed in PHP 8.0.0. Today autoloaders are registered with spl_autoload_register(), in practice usually via the autoloader generated by Composer.

**Do I have to regenerate the autoloader after creating a new class?**  
Not with pure PSR-4 rules; according to the Composer documentation this is precisely an advantage of PSR-4. If you use an optimised class list in production, you must regenerate it with every deployment.

## Sources

- [PHP-FIG: PSR-4 Autoloader](https://www.php-fig.org/psr/psr-4/)
- [PHP Manual: Namespaces overview](https://www.php.net/manual/de/language.namespaces.rationale.php)
- [PHP Manual: Autoloading](https://www.php.net/manual/de/language.oop5.autoload.php)
- [Composer: The composer.json schema](https://getcomposer.org/doc/04-schema.md)
