Kort sagt: Namnrymder är i PHP något i stil med mappar för klassnamn: App\Rechnung\Pdf och Bibliothek\Pdf kan finnas sida vid sida utan att störa varandra. Autoloading ser till att PHP laddar en klass först när den används för första gången. Standarden PSR-4 anger hur ett klassnamn blir en filsökväg; Composer genererar sedan den passande autoloadern. Eftersom autoloadern körs vid varje förfrågan hör den till det första som kontrolleras efter en säkerhetsincident.
Varför PHP behöver namnrymder
Namnrymder finns sedan PHP 5.3.0. Dessförinnan delade alla klasser och funktioner på ett enda globalt namnutrymme. Hette två bibliotek Logger uppstod en konflikt. Utvecklare hjälpte sig med långa namn som Firma_Modul_Unterbereich_Logger.
PHP-manualen nämner två problem som namnrymder löser: namnkollisioner mellan egen kod, PHP-interna klasser och tredjepartsbibliotek, samt överlånga namn som bara uppstod för att kringgå de kollisionerna. För beslutsfattare betyder det: Först namnrymder gjorde det praktiskt möjligt att kombinera dussintals externa paket i ett projekt, som det idag är vanligt med Composer.
Namnrymder i praktiken: namespace, use, alias
En fil deklarerar sin namnrymd i det första uttrycket. Med use hämtar man in klasser från andra namnrymder, om så önskas under ett kortare namn.
<?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 fullständiga namnet på den här klassen är App\Rechnung\PdfErzeuger. Det inledande omvända snedstrecket vid \sprintf hänvisar uttryckligen till den globala PHP-funktionen.
Autoloading: ladda klasser vid behov
Utan autoloading måste varje skript binda in alla nödvändiga filer med require. Med spl_autoload_register() registrerar man i stället en funktion som PHP anropar så snart en okänd klass, ett gränssnitt, en trait eller en enum används. Den får klassnamnet och laddar den passande filen.
<?php
spl_autoload_register(function (string $klasse): void {
$praefix = 'App\\';
$basis = __DIR__ . '/src/';
if (!str_starts_with($klasse, $praefix)) {
return; // inte ansvarig, nästa autoloader får ta över
}
$datei = $basis . str_replace('\\', '/', substr($klasse, strlen($praefix))) . '.php';
if (is_file($datei)) {
require $datei;
}
});
spl_autoload_register() kan anropas flera gånger. PHP frågar då de registrerade autoloaderna efter varandra tills en av dem har laddat klassen. I praktiken har stora applikationer ofta flera: Composers autoloader för bibliotek, en egen för CMS:et och ytterligare från plugin eller moduler. För administratörer betyder det: Vilken kod som faktiskt laddas vid en förfrågan följer av samspelet mellan alla de här autoloaderna och inte bara av katalogstrukturen.
Manualen avråder bestämt från att kasta exceptions i en autoloader; PSR-4 förbjuder det uttryckligen. Den äldre funktionen __autoload() markerades som föråldrad med PHP 7.2.0 och togs bort med PHP 8.0.0.
PSR-4: från klassnamn till filsökväg
PSR-4 är en standard från PHP-FIG. Ett fullständigt klassnamn börjar med en tillverkarnamnrymd. Ett prefix av namnrymden kopplas till en baskatalog, resten av namnet ger underkataloger, och filen slutar på .php. Skiftläget måste stämma exakt. Så ser kopplingen ut i composer.json:
{
"autoload": {
"psr-4": { "App\\": "src/" }
}
}
| Klassnamn | Fil |
|---|---|
App\Kunde\Kunde |
src/Kunde/Kunde.php |
App\Rechnung\PdfErzeuger |
src/Rechnung/PdfErzeuger.php |
App\Rechnung\Pdf\Vorlage |
src/Rechnung/Pdf/Vorlage.php |
Ett klassiskt snubbelstein är skiftläget. På utvecklingsdatorer med Windows eller macOS skiljer filsystemet ofta inte mellan Kunde.php och kunde.php, på en Linux-server gör det det. En applikation som fungerar lokalt hittar då inte en klass på servern. PSR-4-regeln att använda namn med exakt rätt stavning förhindrar sådana överraskningar vid leverans.
Vid sidan av psr-4 har Composer classmap för kod utan standardstruktur och files för filer som laddas vid varje förfrågan, till exempel hjälpfunktioner. Fler standarder från PHP-FIG beskriver sidan PSR-standarder.
Optimera autoloadern i produktion
I produktion bör autoloadern helst inte längre söka i filsystemet utan slå upp i en färdig lista. Composer erbjuder två nivåer för det:
composer install --no-dev --optimize-autoloaderomvandlar PSR-4-reglerna till en klasslista. Enligt Composers dokumentation rekommenderas det för produktion.--classmap-authoritativegår längre: Klasser laddas uteslutande från listan. Filer som inte finns med laddar autoloadern då inte alls.- Vid varje leverans genereras listan om, så att nya klasser hittas.
Autoloading och säkerhet efter PHP2Shell
PHP2Shell gäller PHP-tolken, inte autoloadern. Kravet kvarstår: uppdateringen till PHP 8.5.12, 8.4.27, 8.3.36 eller 8.2.35 och omstart av alla workers. Efter en möjlig incident förtjänar autoloadern ändå särskild uppmärksamhet: vendor/autoload.php och alla filer som anges under files körs vid varje förfrågan. En rad som smugglats in där verkar alltså på hela webbplatsen, utan att någon iögonfallande ny fil ligger i uppladdningsmappen.
Kontrollera därför om vendor och autoload-filerna stämmer med det granskade läget i versionshanteringen. Användbara är inläggen Hitta nyligen ändrade filer och Jämför CMS-kärnfiler med originalet. Vid tvivel är en nygenererad vendor från låsfilen säkrare än varje enskild reparation.
Hur hjälper PHP SOS konkret?
- Vi jämför
vendor, autoloader och ingångsfiler med det granskade läget och markerar varje avvikelse. - Vi återställer paketbeståndet från låsfilen och ställer in en optimerad autoloader.
- Vi kontrollerar att bara den publika mappen ligger i webbroten och att källkod inte kan nås direkt via URL.
- Vid angrepp tar vi hand om saneringen inom ramen för skadlig kod-borttagning och dokumenterar resultatet.
Vanliga frågor
Sedan när finns namnrymder i PHP?
Sedan PHP 5.3.0. Enligt manualen löser de två problem: namnkollisioner mellan egen kod, PHP och tredjepartsbibliotek samt överlånga klassnamn som bara uppstod för att undvika sådana kollisioner.
Vad är skillnaden mellan PSR-0 och PSR-4?
Båda kopplar klassnamn till filsökvägar. Med PSR-4 upprepas inte namnrymdsprefixet i filsökvägen, vilket ger plattare kataloger. PSR-0 är klassat som föråldrat av PHP-FIG, PSR-4 är den rekommenderade standarden.
Fungerar __autoload() fortfarande?
Nej. __autoload() markerades som föråldrad med PHP 7.2.0 och togs bort med PHP 8.0.0. Idag registrerar man autoloaders med spl_autoload_register(), i praktiken oftast via den autoloader som Composer genererar.
Måste jag generera om autoloadern när jag skapar en ny klass?
Med rena PSR-4-regler behövs det inte, enligt Composers dokumentation är det just en fördel med PSR-4. Den som använder en optimerad klasslista i produktion måste generera om den vid varje leverans.