# Vardų erdvės ir autoloading (PSR-4)

> PHP vardų erdvės ir autoloading su PSR-4: nuo klasės pavadinimo iki failo kelio, spl_autoload_register, Composer autoloader ir patikra po incidentų.

Šaltinis: https://phpsos.de/lt/php/namespaces-autoloading/  
Būsena: 2026-10-25  
Teikėjas: PHP SOS, PHP avarinė pagalba ir serverio sauga. Skubi pagalba per „WhatsApp“: https://wa.me/491736494914?text=Sveiki%2C%20PHP%20SOS%2C%20mums%20reikia%20pagalbos%20su%20m%C5%ABs%C5%B3%20PHP%20serveriu.%20%C4%AEmon%C4%97%3A%20%E2%80%A6%20Svetain%C4%97%3A%20%E2%80%A6

**Trumpai:** Vardų erdvės PHP yra tarsi aplankai klasių pavadinimams: `App\Rechnung\Pdf` ir `Bibliothek\Pdf` gali egzistuoti greta, netrukdydamos viena kitai. Autoloading užtikrina, kad PHP klasę įkeltų tik tada, kai jos pirmą kartą prireikia. Standartas PSR-4 nustato, kaip iš klasės pavadinimo gaunamas failo kelias; Composer paskui sukuria tinkamą autoloader. Kadangi šis autoloader veikia per kiekvieną užklausą, po saugumo incidento jis patenka tarp pirmųjų dalykų, kuriuos reikia patikrinti.

## Kodėl PHP reikia vardų erdvių

Vardų erdvės egzistuoja nuo PHP 5.3.0. Anksčiau visos klasės ir funkcijos dalijosi viena globalia vardų erdve. Jei dvi bibliotekos vadindavosi `Logger`, kildavo trikdis. Kūrėjai išsisukdavo ilgais pavadinimais, tokiais kaip `Firma_Modul_Unterbereich_Logger`.

PHP vadovas nurodo dvi problemas, kurias išsprendžia vardų erdvės: pavadinimų kolizijas tarp savo kodo, vidinių PHP klasių ir trečiųjų šalių bibliotekų, taip pat pernelyg ilgus pavadinimus, atsiradusius tik tokioms kolizijoms apeiti. Sprendimų priėmėjams tai reiškia: tik vardų erdvės padarė praktiška viename projekte derinti dešimtis svetimų paketų, kaip šiandien įprasta su [Composer](https://phpsos.de/lt/php/composer/).

## Vardų erdvės praktikoje: namespace, use, slapyvardžiai

Failas savo vardų erdvę deklaruoja pirmajame sakinyje. Su `use` į failą įtraukiamos klasės iš kitų vardų erdvių, pageidaujant trumpesniu pavadinimu.

```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);
    }
}
```

Visas šios klasės pavadinimas yra `App\Rechnung\PdfErzeuger`. Pirmaujantis atvirkštinis brūkšnys prie `\sprintf` aiškiai nurodo globaliąją PHP funkciją.

## Autoloading: klasių įkėlimas pagal poreikį

Be autoloading kiekvienas skriptas visus reikalingus failus turėtų įtraukti su `require`. Vietoj to su `spl_autoload_register()` užregistruojama funkcija, kurią PHP iškviečia, kai tik panaudojama nežinoma klasė, sąsaja, trait ar enum. Ji gauna klasės pavadinimą ir įkelia tinkamą failą.

```php
<?php
spl_autoload_register(function (string $klasse): void {
    $praefix = 'App\\';
    $basis   = __DIR__ . '/src/';

    if (!str_starts_with($klasse, $praefix)) {
        return; // neatsakingas, eilė kitam autoloader
    }
    $datei = $basis . str_replace('\\', '/', substr($klasse, strlen($praefix))) . '.php';
    if (is_file($datei)) {
        require $datei;
    }
});
```

`spl_autoload_register()` galima iškviesti kelis kartus. Tuomet PHP užregistruotų autoloader'ių teiraujasi paeiliui, kol vienas klasę įkelia. Praktikoje didelės programos dažnai turi kelis: Composer autoloader bibliotekoms, savą CMS autoloader ir kitus iš papildinių ar modulių. Administratoriams tai reiškia: koks kodas per užklausą iš tikrųjų įkeliamas, lemia visų šių autoloader'ių sąveika, o ne vien aplankų struktūra.

Vadovas primygtinai nerekomenduoja autoloader'yje mesti išimčių; PSR-4 tai aiškiai draudžia. Senesnė funkcija `__autoload()` su PHP 7.2.0 pažymėta kaip pasenusi, o su PHP 8.0.0 pašalinta.

## PSR-4: nuo klasės pavadinimo iki failo kelio

PSR-4 yra PHP-FIG standartas. Visas klasės pavadinimas prasideda gamintojo vardų erdve. Vardų erdvės prefiksas priskiriamas bazinį katalogui, likusi pavadinimo dalis tampa poaplankiais, o failas baigiasi `.php`. Didžiosios ir mažosios raidės turi tiksliai sutapti. Taip priskyrimas atrodo faile `composer.json`:

```json
{
    "autoload": {
        "psr-4": { "App\\": "src/" }
    }
}
```

| Klasės pavadinimas | Failas |
|---|---|
| `App\Kunde\Kunde` | `src/Kunde/Kunde.php` |
| `App\Rechnung\PdfErzeuger` | `src/Rechnung/PdfErzeuger.php` |
| `App\Rechnung\Pdf\Vorlage` | `src/Rechnung/Pdf/Vorlage.php` |

Klasikinis suklupimo akmuo yra didžiosios ir mažosios raidės. Kūrimo kompiuteriuose su Windows ar macOS failų sistema dažnai neskiria `Kunde.php` ir `kunde.php`, o Linux serveryje skiria. Programa, kuri lokaliai veikia, serveryje klasės nerastų. PSR-4 taisyklė naudoti pavadinimus tiksliai teisinga rašyba tokių netikėtumų diegiant išvengia.

Be `psr-4` Composer žino `classmap` kodui be standartinės struktūros ir `files` failams, kurie įkeliami per kiekvieną užklausą, pavyzdžiui, pagalbinėms funkcijoms. Kitus PHP-FIG standartus aprašo puslapis [PSR standartai](https://phpsos.de/lt/php/psr-standards/).

## Autoloader optimizavimas produkcijoje

Produkcijoje autoloader geriausia nebeieško failų sistemoje, o žiūri į paruoštą sąrašą. Composer tam siūlo du lygius:

1. `composer install --no-dev --optimize-autoloader` PSR-4 taisykles paverčia klasių sąrašu. Pasak Composer dokumentacijos, tai rekomenduojama produkcijai.
2. `--classmap-authoritative` eina toliau: klasės įkeliamos išimtinai iš sąrašo. Neįtrauktų failų autoloader tuomet apskritai neįkelia.
3. Kiekvieno diegimo metu sąrašas sukuriamas iš naujo, kad būtų rastos naujos klasės.

## Autoloading ir saugumas po PHP2Shell

PHP2Shell liečia PHP interpretatorių, o ne autoloader. Privaloma lieka atnaujinti iki PHP 8.5.12, 8.4.27, 8.3.36 ar 8.2.35 ir paleisti iš naujo visus darbinius procesus (worker). Tačiau po galimo incidento autoloader nusipelno ypatingo dėmesio: `vendor/autoload.php` ir visi po `files` įrašyti failai vykdomi per kiekvieną užklausą. Ten įterpta eilutė veikia visoje svetainėje, nors įkėlimų aplanke nėra krentančio į akis naujo failo.

Todėl patikrinkite, ar `vendor` ir autoload failai atitinka patikrintą būseną iš versijų valdymo sistemos. Naudingi straipsniai [Neseniai pakeistų failų paieška](https://phpsos.de/lt/blog/geaenderte-dateien-finden/) ir [CMS branduolio failų palyginimas su originalu](https://phpsos.de/lt/blog/cms-kerndateien-vergleichen/). Abejojant, iš lock failo iš naujo sukurtas `vendor` yra saugesnis nei bet koks pavienis taisymas.

## Kaip PHP SOS padeda konkrečiai?

- Lyginame `vendor`, autoloader ir įėjimo failus su patikrinta būsena ir pažymime kiekvieną nukrypimą.
- Atkuriame paketų rinkinį iš lock failo ir įrengiame optimizuotą autoloader.
- Tikriname, ar žiniatinklio šakniniame kataloge yra tik viešasis aplankas ir ar šaltinio kodas nepasiekiamas tiesiogiai per URL.
- Užkrėtimo atveju atliekame valymą pagal [kenkėjiškos programinės įrangos šalinimo](https://phpsos.de/lt/leistungen/malware-entfernung/) paslaugą ir dokumentuojame rezultatą.


## Dažni klausimai

**Nuo kada PHP yra vardų erdvės?**  
Nuo PHP 5.3.0. Pasak vadovo, jos išsprendžia dvi problemas: pavadinimų kolizijas tarp savo kodo, PHP ir trečiųjų šalių bibliotekų bei pernelyg ilgus klasių pavadinimus, atsiradusius tik tokioms kolizijoms išvengti.

**Kuo skiriasi PSR-0 ir PSR-4?**  
Abu susieja klasių pavadinimus su failų keliais. PSR-4 atveju vardų erdvės prefiksas nekartojamas failo kelyje, todėl katalogai būna plokštesni. PHP-FIG PSR-0 laiko pasenusiu, PSR-4 yra rekomenduojamas standartas.

**Ar __autoload() dar veikia?**  
Ne. __autoload() su PHP 7.2.0 pažymėtas kaip pasenęs, o su PHP 8.0.0 pašalintas. Šiandien autoloader'iai registruojami su spl_autoload_register(), praktikoje dažniausiai per Composer sukurtą autoloader.

**Ar sukūrus naują klasę autoloader reikia generuoti iš naujo?**  
Esant vien PSR-4 taisyklėms ne; pasak Composer dokumentacijos, tai kaip tik yra PSR-4 privalumas. Kas produkcijoje naudoja optimizuotą klasių sąrašą, turi jį sugeneruoti iš naujo kiekvieno diegimo metu.

## Šaltiniai

- [PHP-FIG: PSR-4 autoloader](https://www.php-fig.org/psr/psr-4/)
- [PHP vadovas: vardų erdvės, apžvalga](https://www.php.net/manual/de/language.namespaces.rationale.php)
- [PHP vadovas: autoloading](https://www.php.net/manual/de/language.oop5.autoload.php)
- [Composer: schema composer.json](https://getcomposer.org/doc/04-schema.md)
