En bref : en PHP, les espaces de noms sont un peu comme des dossiers pour les noms de classes : App\Rechnung\Pdf et Bibliothek\Pdf peuvent coexister sans se gêner. L'autoloading fait en sorte que PHP ne charge une classe que lorsqu'elle est utilisée pour la première fois. La norme PSR-4 définit comment un nom de classe devient un chemin de fichier ; Composer génère ensuite l'autoloader correspondant. Comme cet autoloader s'exécute à chaque requête, il fait partie des premiers éléments à contrôler après un incident de sécurité.
Pourquoi PHP a besoin d'espaces de noms
Les espaces de noms existent depuis PHP 5.3.0. Auparavant, toutes les classes et fonctions se partageaient un seul espace de noms global. Si deux bibliothèques s'appelaient Logger, cela coinçait. Les développeurs s'en sortaient avec de longs noms comme Firma_Modul_Unterbereich_Logger.
Le manuel PHP cite deux problèmes que résolvent les espaces de noms : les collisions de noms entre le code propre, les classes internes de PHP et les bibliothèques tierces, ainsi que les noms démesurément longs créés uniquement pour contourner ces collisions. Pour les décideurs, cela signifie que ce sont les espaces de noms qui ont rendu praticable la combinaison de dizaines de paquets externes dans un projet, comme c'est aujourd'hui l'usage avec Composer.
Les espaces de noms en pratique : namespace, use, alias
Un fichier déclare son espace de noms dans sa première instruction. Avec use, on importe des classes d'autres espaces de noms, si on le souhaite sous un nom plus court.
<?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);
}
}
Le nom complet de cette classe est App\Rechnung\PdfErzeuger. L'antislash initial devant \sprintf renvoie explicitement à la fonction PHP globale.
Autoloading : charger les classes à la demande
Sans autoloading, chaque script devrait inclure tous les fichiers nécessaires avec require. Avec spl_autoload_register(), on enregistre à la place une fonction que PHP appelle dès qu'une classe, une interface, un trait ou un enum inconnu est utilisé. Elle reçoit le nom de la classe et charge le fichier correspondant.
<?php
spl_autoload_register(function (string $klasse): void {
$praefix = 'App\\';
$basis = __DIR__ . '/src/';
if (!str_starts_with($klasse, $praefix)) {
return; // pas concerné, au tour de l'autoloader suivant
}
$datei = $basis . str_replace('\\', '/', substr($klasse, strlen($praefix))) . '.php';
if (is_file($datei)) {
require $datei;
}
});
spl_autoload_register() peut être appelée plusieurs fois. PHP interroge alors les autoloaders enregistrés l'un après l'autre, jusqu'à ce que l'un d'eux ait chargé la classe. En pratique, les grandes applications en ont souvent plusieurs : l'autoloader de Composer pour les bibliothèques, un autoloader propre au CMS et d'autres issus de plugins ou de modules. Pour les administrateurs, cela signifie que le code effectivement chargé lors d'une requête résulte de l'interaction de tous ces autoloaders, et non de la seule arborescence de dossiers.
Le manuel déconseille vivement de lever des exceptions dans un autoloader ; PSR-4 l'interdit expressément. L'ancienne fonction __autoload() a été marquée comme obsolète avec PHP 7.2.0 et supprimée avec PHP 8.0.0.
PSR-4 : du nom de classe au chemin du fichier
PSR-4 est une norme du PHP-FIG. Un nom de classe complet commence par un espace de noms de fournisseur. Un préfixe de l'espace de noms est associé à un répertoire de base, le reste du nom donne des sous-dossiers, et le fichier se termine par .php. La casse doit correspondre exactement. Voici à quoi ressemble l'association dans le composer.json :
{
"autoload": {
"psr-4": { "App\\": "src/" }
}
}
| Nom de classe | Fichier |
|---|---|
App\Kunde\Kunde |
src/Kunde/Kunde.php |
App\Rechnung\PdfErzeuger |
src/Rechnung/PdfErzeuger.php |
App\Rechnung\Pdf\Vorlage |
src/Rechnung/Pdf/Vorlage.php |
Un piège classique est la casse. Sur les postes de développement sous Windows ou macOS, le système de fichiers ne distingue souvent pas Kunde.php de kunde.php, contrairement à un serveur Linux. Une application qui fonctionne en local ne trouve alors pas une classe sur le serveur. La règle de PSR-4 qui consiste à utiliser les noms exactement dans la bonne graphie évite de telles surprises lors de la livraison.
Outre psr-4, Composer connaît classmap pour le code sans structure standard et files pour les fichiers chargés à chaque requête, par exemple des fonctions utilitaires. D'autres normes du PHP-FIG sont décrites sur la page Normes PSR.
Optimiser l'autoloader en production
En production, l'autoloader ne devrait idéalement plus chercher dans le système de fichiers, mais consulter une liste toute prête. Composer propose pour cela deux niveaux :
composer install --no-dev --optimize-autoloaderconvertit les règles PSR-4 en une liste de classes. Selon la documentation de Composer, c'est recommandé pour la production.--classmap-authoritativeva plus loin : les classes sont chargées exclusivement depuis la liste. Les fichiers non listés ne sont alors pas du tout chargés par l'autoloader.- À chaque livraison, la liste est régénérée afin que les nouvelles classes soient trouvées.
Autoloading et sécurité après PHP2Shell
PHP2Shell concerne l'interpréteur PHP, non l'autoloader. La mise à jour vers PHP 8.5.12, 8.4.27, 8.3.36 ou 8.2.35 et le redémarrage de tous les workers restent obligatoires. Après un incident possible, l'autoloader mérite toutefois une attention particulière : vendor/autoload.php et tous les fichiers inscrits sous files sont exécutés à chaque requête. Une ligne glissée à cet endroit agit donc sur l'ensemble du site, sans qu'un nouveau fichier suspect ne se trouve dans le dossier d'upload.
Vérifiez donc si vendor et les fichiers d'autoload correspondent à l'état contrôlé du gestionnaire de versions. Les articles Retrouver les fichiers récemment modifiés et Comparer les fichiers cœur du CMS à l'original sont utiles. En cas de doute, un vendor fraîchement régénéré à partir du fichier de verrouillage est plus sûr que toute réparation au cas par cas.
Comment PHP SOS aide-t-il concrètement ?
- Nous comparons
vendor, l'autoloader et les fichiers d'entrée à l'état contrôlé et signalons chaque écart. - Nous reconstituons l'ensemble des paquets à partir du fichier de verrouillage et mettons en place un autoloader optimisé.
- Nous vérifions que seul le dossier public se trouve dans la racine web et que le code source n'est pas directement accessible par URL.
- En cas d'infection, nous assurons le nettoyage dans le cadre de la suppression de malware et documentons le résultat.
Questions fréquentes
Depuis quand les espaces de noms existent-ils en PHP ?
Depuis PHP 5.3.0. Selon le manuel, ils résolvent deux problèmes : les collisions de noms entre le code propre, PHP et les bibliothèques tierces, ainsi que les noms de classes démesurément longs, nés uniquement pour éviter de telles collisions.
Quelle est la différence entre PSR-0 et PSR-4 ?
Les deux associent des noms de classes à des chemins de fichiers. Avec PSR-4, le préfixe d'espace de noms n'est pas répété dans le chemin du fichier, ce qui donne des répertoires plus plats. PSR-0 est classée comme obsolète par le PHP-FIG ; PSR-4 est la norme recommandée.
__autoload() fonctionne-t-elle encore ?
Non. __autoload() a été marquée comme obsolète avec PHP 7.2.0 et supprimée avec PHP 8.0.0. Aujourd'hui, on enregistre les autoloaders avec spl_autoload_register(), en pratique le plus souvent via l'autoloader généré par Composer.
Dois-je régénérer l'autoloader après avoir créé une nouvelle classe ?
Pas avec de simples règles PSR-4 ; selon la documentation de Composer, c'est justement un avantage de PSR-4. Qui utilise en production une liste de classes optimisée doit la régénérer à chaque livraison.