# Namespaces og autoloading (PSR-4)

> PHP-namespaces og autoloading med PSR-4: fra klassenavn til filsti, spl_autoload_register, Composer-autoloaderen og kontrol efter hændelser.

Kilde: https://phpsos.de/da/php/namespaces-autoloading/  
Status: 25.10.2026  
Udbyder: PHP SOS, PHP-nødhjælp og serversikkerhed. Akut hjælp på WhatsApp: https://wa.me/491736494914?text=Hej%20PHP%20SOS%2C%20vi%20har%20brug%20for%20hj%C3%A6lp%20med%20vores%20PHP-server.%20Firma%3A%20%E2%80%A6%20Website%3A%20%E2%80%A6

**Kort sagt:** Namespaces er i PHP noget i retning af mapper til klassenavne: `App\Rechnung\Pdf` og `Bibliothek\Pdf` kan eksistere side om side uden at genere hinanden. Autoloading sørger for, at PHP først indlæser en klasse, når den bruges for første gang. Standarden PSR-4 fastlægger, hvordan et klassenavn bliver til en filsti; Composer genererer derefter den passende autoloader. Fordi denne autoloader kører ved hver forespørgsel, hører den efter en sikkerhedshændelse til de første ting, der kontrolleres.

## Hvorfor PHP har brug for namespaces

Namespaces findes siden PHP 5.3.0. Før delte alle klasser og funktioner ét enkelt globalt navnerum. Hed to biblioteker `Logger`, gik det galt. Udviklere hjalp sig med lange navne som `Firma_Modul_Unterbereich_Logger`.

PHP-manualen nævner to problemer, som namespaces løser: navnekollisioner mellem egen kode, PHP's interne klasser og tredjepartsbiblioteker samt alt for lange navne, der kun er opstået for at omgå disse kollisioner. For beslutningstagere betyder det: Først namespaces har gjort det praktikabelt at kombinere dusinvis af fremmede pakker i ét projekt, som det i dag er sædvanligt med [Composer](https://phpsos.de/da/php/composer/).

## Namespaces i praksis: namespace, use, aliasser

En fil deklarerer sit namespace i den første sætning. Med `use` henter man klasser ind fra andre namespaces, om ønsket under et kortere navn.

```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);
    }
}
```

Det fulde navn på denne klasse er `App\Rechnung\PdfErzeuger`. Den foranstillede backslash ved `\sprintf` henviser udtrykkeligt til den globale PHP-funktion.

## Autoloading: indlæs klasser ved behov

Uden autoloading skulle ethvert script inkludere alle nødvendige filer med `require`. Med `spl_autoload_register()` registrerer man i stedet en funktion, som PHP kalder, så snart en ukendt klasse, et interface, en trait eller en enum bruges. Den får klassenavnet og indlæser den passende fil.

```php
<?php
spl_autoload_register(function (string $klasse): void {
    $praefix = 'App\\';
    $basis   = __DIR__ . '/src/';

    if (!str_starts_with($klasse, $praefix)) {
        return; // ikke ansvarlig, den næste autoloader er på
    }
    $datei = $basis . str_replace('\\', '/', substr($klasse, strlen($praefix))) . '.php';
    if (is_file($datei)) {
        require $datei;
    }
});
```

`spl_autoload_register()` kan kaldes flere gange. PHP spørger så de registrerede autoloadere efter hinanden, indtil en har indlæst klassen. I praksis har store applikationer ofte flere af dem: Composer-autoloaderen til biblioteker, en egen fra CMS'et og flere fra plugins eller moduler. For administratorer betyder det: Hvilken kode der faktisk indlæses ved en forespørgsel, fremgår af samspillet mellem alle disse autoloadere og ikke alene af mappestrukturen.

Manualen fraråder kraftigt at kaste exceptions i en autoloader; PSR-4 forbyder det udtrykkeligt. Den ældre funktion `__autoload()` blev markeret som forældet med PHP 7.2.0 og fjernet med PHP 8.0.0.

## PSR-4: fra klassenavn til filsti

PSR-4 er en standard fra PHP-FIG. Et fuldt klassenavn begynder med et producent-namespace. Et præfiks af namespace'et knyttes til en basismappe, resten af navnet giver undermapper, og filen ender på `.php`. Store og små bogstaver skal stemme nøjagtigt overens. Sådan ser tilknytningen ud i `composer.json`:

```json
{
    "autoload": {
        "psr-4": { "App\\": "src/" }
    }
}
```

| Klassenavn | Fil |
|---|---|
| `App\Kunde\Kunde` | `src/Kunde/Kunde.php` |
| `App\Rechnung\PdfErzeuger` | `src/Rechnung/PdfErzeuger.php` |
| `App\Rechnung\Pdf\Vorlage` | `src/Rechnung/Pdf/Vorlage.php` |

En klassisk faldgrube er brugen af store og små bogstaver. På udviklingsmaskiner med Windows eller macOS skelner filsystemet ofte ikke mellem `Kunde.php` og `kunde.php`, på en Linux-server gør det. En applikation, der kører lokalt, finder så ikke en klasse på serveren. Reglen fra PSR-4 om at bruge navne i nøjagtigt den rette stavemåde forhindrer sådanne overraskelser ved leveringen.

Ud over `psr-4` kender Composer `classmap` til kode uden standardstruktur og `files` til filer, der indlæses ved hver forespørgsel, f.eks. hjælpefunktioner. Flere standarder fra PHP-FIG beskriver siden [PSR-standarder](https://phpsos.de/da/php/psr-standards/).

## Optimér autoloaderen i produktion

I produktion søger autoloaderen bedst ikke længere i filsystemet, men slår op i en færdig liste. Composer tilbyder hertil to trin:

1. `composer install --no-dev --optimize-autoloader` omdanner PSR-4-reglerne til en klasseliste. Det er ifølge Composer-dokumentationen anbefalet til produktion.
2. `--classmap-authoritative` går videre: Klasser indlæses udelukkende fra listen. Filer, der ikke er opført, indlæser autoloaderen så slet ikke.
3. Ved hver levering genereres listen på ny, så nye klasser findes.

## Autoloading og sikkerhed efter PHP2Shell

PHP2Shell angår PHP-fortolkeren, ikke autoloaderen. Et must er fortsat opdateringen til PHP 8.5.12, 8.4.27, 8.3.36 eller 8.2.35 og genstart af alle workers. Efter en mulig hændelse fortjener autoloaderen dog særlig opmærksomhed: `vendor/autoload.php` og alle filer, der er opført under `files`, udføres ved hver forespørgsel. En linje, der er smuglet ind dér, virker altså på hele websitet, uden at en iøjnefaldende ny fil ligger i upload-mappen.

Kontrollér derfor, om `vendor` og autoload-filerne passer til den kontrollerede tilstand i versionsstyringen. Hjælpsomme er indlæggene [Find nyligt ændrede filer](https://phpsos.de/da/blog/geaenderte-dateien-finden/) og [Sammenlign CMS-kernefiler med originalen](https://phpsos.de/da/blog/cms-kerndateien-vergleichen/). I tvivlstilfælde er en nygenereret `vendor` ud fra lock-filen sikrere end enhver enkeltreparation.

## Hvordan hjælper PHP SOS konkret?

- Vi sammenligner `vendor`, autoloader og indgangsfiler med den kontrollerede tilstand og markerer enhver afvigelse.
- Vi genskaber pakkebeholdningen ud fra lock-filen og opsætter en optimeret autoloader.
- Vi kontrollerer, om kun den offentlige mappe ligger i webroot, og om kildekode ikke kan nås direkte via URL.
- Ved angreb overtager vi oprydningen som led i [malwarefjernelsen](https://phpsos.de/da/leistungen/malware-entfernung/) og dokumenterer resultatet.


## Ofte stillede spørgsmål

**Siden hvornår findes der namespaces i PHP?**  
Siden PHP 5.3.0. Ifølge manualen løser de to problemer: navnekollisioner mellem egen kode, PHP og tredjepartsbiblioteker samt alt for lange klassenavne, der kun opstod for at undgå sådanne kollisioner.

**Hvad er forskellen på PSR-0 og PSR-4?**  
Begge afbilder klassenavne på filstier. Ved PSR-4 gentages namespace-præfikset ikke i filstien, hvilket giver fladere mappestrukturer. PSR-0 er hos PHP-FIG klassificeret som forældet, PSR-4 er den anbefalede standard.

**Virker __autoload() stadig?**  
Nej. __autoload() blev markeret som forældet med PHP 7.2.0 og fjernet med PHP 8.0.0. I dag registrerer man autoloadere med spl_autoload_register(), i praksis oftest via den autoloader, Composer genererer.

**Skal jeg generere autoloaderen igen, når jeg har oprettet en ny klasse?**  
Ved rene PSR-4-regler ikke; ifølge Composer-dokumentationen er det netop en fordel ved PSR-4. Den, der bruger en optimeret klasseliste i produktion, skal generere den igen ved hver levering.

## Kilder

- [PHP-FIG: PSR-4 Autoloader](https://www.php-fig.org/psr/psr-4/)
- [PHP-manualen: Namespaces, overblik](https://www.php.net/manual/de/language.namespaces.rationale.php)
- [PHP-manualen: Autoloading](https://www.php.net/manual/de/language.oop5.autoload.php)
- [Composer: Skemaet for composer.json](https://getcomposer.org/doc/04-schema.md)
