# Nimiavaruudet ja automaattinen lataus (PSR-4)

> PHP-nimiavaruudet ja automaattinen lataus PSR-4:llä: luokan nimestä tiedostopolkuun, spl_autoload_register, Composerin lataaja ja tarkastus tietoturvapoikkeaman jälkeen.

Lähde: https://phpsos.de/fi/php/namespaces-autoloading/  
Tilanne: 25.10.2026  
Palveluntarjoaja: PHP SOS, PHP-hätäapu ja palvelimen tietoturva. Pikaapu WhatsAppilla: https://wa.me/491736494914?text=Hei%20PHP%20SOS%2C%20tarvitsemme%20apua%20PHP-palvelimemme%20kanssa.%20Yritys%3A%20%E2%80%A6%20Verkkosivusto%3A%20%E2%80%A6

**Lyhyesti:** Nimiavaruudet ovat PHP:ssä eräänlaisia kansioita luokkien nimille: `App\Rechnung\Pdf` ja `Bibliothek\Pdf` voivat olla rinnakkain häiritsemättä toisiaan. Automaattinen lataus huolehtii siitä, että PHP lataa luokan vasta, kun sitä tarvitaan ensimmäisen kerran. Standardi PSR-4 määrittää, miten luokan nimestä tulee tiedostopolku; Composer tuottaa sen jälkeen sopivan lataajan. Koska tämä lataaja suoritetaan jokaisella pyynnöllä, se kuuluu tietoturvapoikkeaman jälkeen ensimmäisiin tarkastettaviin asioihin.

## Miksi PHP tarvitsee nimiavaruuksia

Nimiavaruuksia on ollut versiosta PHP 5.3.0 lähtien. Sitä ennen kaikki luokat ja funktiot jakoivat yhden ainoan globaalin nimiavaruuden. Jos kaksi kirjastoa oli nimeltään `Logger`, syntyi törmäys. Kehittäjät auttoivat itseään pitkillä nimillä, kuten `Firma_Modul_Unterbereich_Logger`.

PHP-käsikirja mainitsee kaksi ongelmaa, jotka nimiavaruudet ratkaisevat: nimitörmäykset oman koodin, PHP:n sisäisten luokkien ja kolmansien osapuolten kirjastojen välillä sekä ylipitkät nimet, jotka syntyivät vain näiden törmäysten kiertämiseksi. Päättäjälle tämä tarkoittaa: vasta nimiavaruudet ovat tehneet käytännölliseksi yhdistää projektissa kymmeniä vieraita paketteja, kuten [Composerin](https://phpsos.de/fi/php/composer/) kanssa nykyisin tehdään.

## Nimiavaruudet käytännössä: namespace, use, aliakset

Tiedosto ilmoittaa nimiavaruutensa ensimmäisessä lauseessa. Käskyllä `use` tuodaan luokkia muista nimiavaruuksista, halutessa lyhyemmällä nimellä.

```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);
    }
}
```

Tämän luokan täydellinen nimi on `App\Rechnung\PdfErzeuger`. Alussa oleva kenoviiva kohdassa `\sprintf` viittaa nimenomaisesti globaaliin PHP-funktioon.

## Automaattinen lataus: luokat ladataan tarpeen mukaan

Ilman automaattista latausta jokaisen komentosarjan pitäisi liittää tarvitsemansa tiedostot käskyllä `require`. Funktiolla `spl_autoload_register()` rekisteröidään sen sijaan funktio, jonka PHP kutsuu heti, kun tuntematon luokka, rajapinta, trait tai enum otetaan käyttöön. Se saa luokan nimen ja lataa sopivan tiedoston.

```php
<?php
spl_autoload_register(function (string $klasse): void {
    $praefix = 'App\\';
    $basis   = __DIR__ . '/src/';

    if (!str_starts_with($klasse, $praefix)) {
        return; // ei vastuulla, seuraava lataaja on vuorossa
    }
    $datei = $basis . str_replace('\\', '/', substr($klasse, strlen($praefix))) . '.php';
    if (is_file($datei)) {
        require $datei;
    }
});
```

Funktiota `spl_autoload_register()` voi kutsua useita kertoja. PHP kysyy silloin rekisteröityjä lataajia vuorotellen, kunnes jokin on ladannut luokan. Käytännössä suurissa sovelluksissa on usein useita: Composerin lataaja kirjastoille, CMS:n oma sekä lisäosien tai moduulien lataajat. Ylläpitäjälle tämä tarkoittaa: se, mikä koodi pyynnöllä todella ladataan, määräytyy kaikkien näiden lataajien yhteispelistä eikä pelkästään kansiorakenteesta.

Käsikirja neuvoo painokkaasti olemaan heittämättä poikkeuksia lataajassa; PSR-4 kieltää sen nimenomaisesti. Vanhempi funktio `__autoload()` merkittiin vanhentuneeksi versiossa PHP 7.2.0 ja poistettiin versiossa PHP 8.0.0.

## PSR-4: luokan nimestä tiedostopolkuun

PSR-4 on PHP-FIG:n standardi. Täydellinen luokan nimi alkaa valmistajan nimiavaruudella. Nimiavaruuden etuliite yhdistetään perushakemistoon, loppuosa nimestä muodostaa alikansiot, ja tiedosto päättyy `.php`. Isojen ja pienten kirjainten on täsmättävä tarkasti. Näin yhdistäminen näkyy tiedostossa `composer.json`:

```json
{
    "autoload": {
        "psr-4": { "App\\": "src/" }
    }
}
```

| Luokan nimi | Tiedosto |
|---|---|
| `App\Kunde\Kunde` | `src/Kunde/Kunde.php` |
| `App\Rechnung\PdfErzeuger` | `src/Rechnung/PdfErzeuger.php` |
| `App\Rechnung\Pdf\Vorlage` | `src/Rechnung/Pdf/Vorlage.php` |

Klassinen kompastuskivi on isojen ja pienten kirjainten käyttö. Windows- tai macOS-kehityskoneilla tiedostojärjestelmä ei usein erota tiedostoja `Kunde.php` ja `kunde.php` toisistaan, mutta Linux-palvelimella erottaa. Paikallisesti toimiva sovellus ei silloin löydä luokkaa palvelimella. PSR-4:n sääntö käyttää nimiä täsmälleen oikein kirjoitettuina estää tällaiset yllätykset toimituksessa.

Tiedoston `psr-4` lisäksi Composer tuntee `classmap`-määrityksen koodille, jolla ei ole vakiorakennetta, sekä `files`-määrityksen tiedostoille, jotka ladataan jokaisella pyynnöllä, esimerkiksi apufunktioille. Muita PHP-FIG:n standardeja kuvaa sivu [PSR-standardit](https://phpsos.de/fi/php/psr-standards/).

## Lataajan optimointi tuotannossa

Tuotannossa lataajan on parasta olla etsimättä enää tiedostojärjestelmästä vaan hakea valmiista listasta. Composer tarjoaa tähän kaksi tasoa:

1. `composer install --no-dev --optimize-autoloader` muuntaa PSR-4-säännöt luokkalistaksi. Composerin dokumentaation mukaan se on suositeltu tuotantoon.
2. `--classmap-authoritative` menee pidemmälle: luokat ladataan yksinomaan listasta. Listaan kuulumattomia tiedostoja lataaja ei silloin lataa lainkaan.
3. Lista luodaan uudelleen jokaisen toimituksen yhteydessä, jotta uudet luokat löytyvät.

## Automaattinen lataus ja tietoturva PHP2Shellin jälkeen

PHP2Shell koskee PHP-tulkkia, ei lataajaa. Pakollisia pysyvät päivitys versioon PHP 8.5.12, 8.4.27, 8.3.36 tai 8.2.35 ja kaikkien worker-prosessien uudelleenkäynnistys. Mahdollisen poikkeaman jälkeen lataaja ansaitsee kuitenkin erityistä huomiota: `vendor/autoload.php` ja kaikki kohdassa `files` mainitut tiedostot suoritetaan jokaisella pyynnöllä. Sinne livahtanut rivi vaikuttaa siis koko verkkosivustoon ilman, että latauskansiossa on huomiota herättävää uutta tiedostoa.

Tarkistakaa siksi, vastaavatko `vendor` ja lataustiedostot versionhallinnan tarkastettua tilaa. Hyödyllisiä ovat artikkelit [Äskettäin muuttuneiden tiedostojen löytäminen](https://phpsos.de/fi/blog/geaenderte-dateien-finden/) ja [CMS:n ydintiedostojen vertailu alkuperäiseen](https://phpsos.de/fi/blog/cms-kerndateien-vergleichen/). Epäselvässä tilanteessa lukitustiedostosta uudelleen tuotettu `vendor` on turvallisempi kuin yksittäinen korjaus.

## Miten PHP SOS auttaa konkreettisesti?

- Vertaamme tiedostoja `vendor`, lataaja ja sisäänkäyntitiedostot tarkastettuun tilaan ja merkitsemme jokaisen poikkeaman.
- Palautamme pakettikannan lukitustiedostosta ja otamme käyttöön optimoidun lataajan.
- Tarkistamme, että verkkojuuressa on vain julkinen kansio eikä lähdekoodi ole suoraan tavoitettavissa URL-osoitteella.
- Saastumistapauksessa hoidamme puhdistuksen [haittaohjelmien poiston](https://phpsos.de/fi/leistungen/malware-entfernung/) puitteissa ja dokumentoimme tuloksen.


## Usein kysytyt kysymykset

**Mistä lähtien PHP:ssä on ollut nimiavaruuksia?**  
Versiosta PHP 5.3.0 lähtien. Käsikirjan mukaan ne ratkaisevat kaksi ongelmaa: nimitörmäykset oman koodin, PHP:n ja kolmansien osapuolten kirjastojen välillä sekä ylipitkät luokkanimet, jotka syntyivät vain tällaisten törmäysten välttämiseksi.

**Mikä on ero PSR-0:n ja PSR-4:n välillä?**  
Molemmat kuvaavat luokkien nimet tiedostopoluiksi. PSR-4:ssä nimiavaruuden etuliitettä ei toisteta tiedostopolussa, mikä tuottaa matalamman hakemistorakenteen. PHP-FIG on luokitellut PSR-0:n vanhentuneeksi, ja PSR-4 on suositeltu standardi.

**Toimiiko __autoload() vielä?**  
Ei toimi. __autoload() merkittiin vanhentuneeksi versiossa PHP 7.2.0 ja poistettiin versiossa PHP 8.0.0. Nykyisin lataajat rekisteröidään funktiolla spl_autoload_register(), käytännössä yleensä Composerin tuottaman lataajan kautta.

**Pitääkö lataaja luoda uudelleen, kun luo uuden luokan?**  
Puhtailla PSR-4-säännöillä ei tarvitse; Composerin dokumentaation mukaan se on juuri PSR-4:n etu. Jos tuotannossa käytetään optimoitua luokkalistaa, se on luotava uudelleen jokaisen toimituksen yhteydessä.

## Lähteet

- [PHP-FIG: PSR-4 Autoloader](https://www.php-fig.org/psr/psr-4/)
- [PHP-käsikirja: nimiavaruudet, yleiskatsaus](https://www.php.net/manual/de/language.namespaces.rationale.php)
- [PHP-käsikirja: automaattinen lataus](https://www.php.net/manual/de/language.oop5.autoload.php)
- [Composer: The composer.json schema](https://getcomposer.org/doc/04-schema.md)
