Röviden: A névterek a PHP-ban az osztálynevek mappáihoz hasonlítanak: az App\Rechnung\Pdf és a Bibliothek\Pdf egymás mellett létezhet anélkül, hogy zavarnák egymást. Az autoloading gondoskodik arról, hogy a PHP egy osztályt csak akkor töltsön be, amikor először szükség van rá. A PSR-4 szabvány meghatározza, hogyan lesz az osztálynévből fájlútvonal; a Composer ehhez létrehozza a megfelelő autoloadert. Mivel ez az autoloader minden kérésnél lefut, biztonsági incidens után az elsők között kell ellenőrizni.
Miért van szüksége a PHP-nak névterekre
Névterek a PHP 5.3.0 óta léteznek. Előtte minden osztály és függvény egyetlen globális névtéren osztozott. Ha két programkönyvtárat is Logger-nek hívtak, baj lett. A fejlesztők hosszú nevekkel segítettek magukon, mint a Firma_Modul_Unterbereich_Logger.
A PHP-kézikönyv két problémát nevez meg, amelyeket a névterek megoldanak: a saját kód, a PHP belső osztályai és a harmadik fél programkönyvtárai közötti névütközéseket, valamint a túl hosszú neveket, amelyek csak ezeknek az ütközéseknek a megkerülésére keletkeztek. A döntéshozók számára ez azt jelenti: csak a névterek tették járhatóvá, hogy egy projektben több tucat idegen csomagot kombináljanak, ahogyan ez a Composerrel ma megszokott.
Névterek a gyakorlatban: namespace, use, aliasok
Egy fájl az első utasításban deklarálja a névterét. A use segítségével más névterekből hozhat be osztályokat, kívánság szerint rövidebb néven.
<?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);
}
}
Ennek az osztálynak a teljes neve App\Rechnung\PdfErzeuger. A \sprintf előtti vezető fordított törtvonal kifejezetten a globális PHP-függvényre hivatkozik.
Autoloading: osztályok betöltése szükség esetén
Autoloading nélkül minden szkriptnek require-rel kellene beágyaznia az összes szükséges fájlt. Az spl_autoload_register() segítségével ehelyett egy olyan függvényt regisztrálnak, amelyet a PHP akkor hív meg, amint egy ismeretlen osztályt, interfészt, trait-et vagy enumot használnak. A függvény megkapja az osztálynevet, és betölti a megfelelő fájlt.
<?php
spl_autoload_register(function (string $klasse): void {
$praefix = 'App\\';
$basis = __DIR__ . '/src/';
if (!str_starts_with($klasse, $praefix)) {
return; // nem illetékes, a következő autoloader jön
}
$datei = $basis . str_replace('\\', '/', substr($klasse, strlen($praefix))) . '.php';
if (is_file($datei)) {
require $datei;
}
});
Az spl_autoload_register() többször is hívható. A PHP ilyenkor egymás után kérdezi a regisztrált autoloadereket, amíg egy be nem tölti az osztályt. A gyakorlatban a nagy alkalmazásoknak gyakran több is van belőlük: a Composer-autoloader a programkönyvtáraknak, a CMS saját autoloadere, és további autoloaderek a bővítményektől vagy modulokból. Az adminisztrátorok számára ez azt jelenti: hogy egy kérésnél valójában melyik kód töltődik be, az mindezen autoloaderek együttműködéséből adódik, nem pusztán a mappaszerkezetből.
A kézikönyv határozottan lemond arról, hogy egy autoloaderben kivételt dobjanak; a PSR-4 ezt kifejezetten tiltja. A régebbi __autoload() függvényt a PHP 7.2.0 elavultnak jelölte, a PHP 8.0.0-ban pedig eltávolították.
PSR-4: az osztálynévtől a fájl útvonaláig
A PSR-4 a PHP-FIG szabványa. A teljes osztálynév gyártói névtérrel kezdődik. A névtér egy előtagját egy alapkönyvtárhoz rendelik, a név többi része almappákat ad, a fájl pedig .php kiterjesztéssel végződik. A kis- és nagybetűknek pontosan egyezniük kell. Így néz ki a hozzárendelés a composer.json-ban:
{
"autoload": {
"psr-4": { "App\\": "src/" }
}
}
| Osztálynév | Fájl |
|---|---|
App\Kunde\Kunde |
src/Kunde/Kunde.php |
App\Rechnung\PdfErzeuger |
src/Rechnung/PdfErzeuger.php |
App\Rechnung\Pdf\Vorlage |
src/Rechnung/Pdf/Vorlage.php |
Klasszikus buktató a kis- és nagybetűk kérdése. A Windowsos vagy macOS-es fejlesztői gépeken a fájlrendszer gyakran nem különbözteti meg a Kunde.php-t és a kunde.php-t, egy Linux-szerveren viszont igen. Egy helyben működő alkalmazás ilyenkor a szerveren nem találja az osztályt. A PSR-4 szabálya, hogy a neveket pontosan a helyes írásmóddal kell használni, megelőzi az ilyen meglepetéseket a kiszállításkor.
A psr-4 mellett a Composer ismeri a classmap-et a szabványos szerkezet nélküli kódhoz, és a files-t azokhoz a fájlokhoz, amelyek minden kérésnél betöltődnek, például segédfüggvényekhez. A PHP-FIG további szabványait a PSR-szabványok oldal írja le.
Az autoloader optimalizálása éles üzemben
Éles üzemben az autoloader a legjobb, ha már nem a fájlrendszerben keres, hanem egy kész listában néz utána. A Composer ehhez két fokozatot kínál:
- A
composer install --no-dev --optimize-autoloadera PSR-4 szabályokat osztálylistává alakítja. Ez a Composer dokumentációja szerint éles üzemre ajánlott. - A
--classmap-authoritativetovábbmegy: az osztályokat kizárólag a listából tölti be. A fel nem sorolt fájlokat az autoloader ilyenkor egyáltalán nem tölti be. - Minden kiszállításkor újra kell generálni a listát, hogy az új osztályokat megtalálja.
Autoloading és biztonság a PHP2Shell után
A PHP2Shell a PHP-értelmezőt érinti, nem az autoloadert. Továbbra is kötelező a frissítés a PHP 8.5.12, 8.4.27, 8.3.36 vagy 8.2.35 verzióra, és az összes worker újraindítása. Egy lehetséges incidens után azonban az autoloader különös figyelmet érdemel: a vendor/autoload.php és a files alatt felvett összes fájl minden kérésnél lefut. Az oda beszúrt egyetlen sor tehát az egész weboldalon hat, anélkül hogy feltűnő új fájl lenne a feltöltési mappában.
Ellenőrizze ezért, hogy a vendor és az autoload-fájlok egyeznek-e a verziókezelésből származó, ellenőrzött állapottal. Hasznosak a Nemrég módosított fájlok megkeresése és a CMS-magfájlok összehasonlítása az eredetivel cikkek. Kétség esetén a lock-fájlból frissen előállított vendor biztonságosabb bármely egyedi javításnál.
Hogyan segít konkrétan a PHP SOS?
- Összevetjük a
vendor-t, az autoloadert és a belépési fájlokat az ellenőrzött állapottal, és megjelölünk minden eltérést. - A csomagállományt újra előállítjuk a lock-fájlból, és optimalizált autoloadert állítunk be.
- Ellenőrizzük, hogy csak a nyilvános mappa van-e a webgyökérben, és a forráskód nem érhető-e el közvetlenül URL-en.
- Fertőzés esetén a kártevőeltávolítás keretében elvégezzük a tisztítást, és dokumentáljuk az eredményt.
Gyakori kérdések
Mióta léteznek névterek a PHP-ban?
A PHP 5.3.0 óta. A kézikönyv szerint két problémát oldanak meg: az saját kód, a PHP és a harmadik fél programkönyvtárai közötti névütközéseket, valamint a túl hosszú osztályneveket, amelyek csak az ilyen ütközések elkerülésére keletkeztek.
Mi a különbség a PSR-0 és a PSR-4 között?
Mindkettő osztályneveket képez le fájlútvonalakra. A PSR-4-nél a névtér-előtag nem ismétlődik a fájl útvonalában, így laposabb könyvtárszerkezet jön létre. A PSR-0-t a PHP-FIG elavultnak minősítette, a PSR-4 az ajánlott szabvány.
Működik még az __autoload()?
Nem. Az __autoload()-ot a PHP 7.2.0 elavultnak jelölte, a PHP 8.0.0-ban pedig eltávolították. Ma az autoloadereket az spl_autoload_register() függvénnyel regisztrálják, a gyakorlatban többnyire a Composer által generált autoloaderen keresztül.
Újra kell generálni az autoloadert egy új osztály létrehozása után?
Tiszta PSR-4 szabályoknál nem, a Composer dokumentációja szerint éppen ez a PSR-4 egyik előnye. Aki éles üzemben optimalizált osztálylistát használ, annak minden kiszállításkor újra kell generálnia.