Leçon 7/7 9 min

Namespaces & autoloading

Namespaces PHP, collisions de noms évitées et autoloading PSR-4 via Composer. Structure d'un vrai projet PHP.

Le problème : trop de classes, des noms qui se cognent

Dans un vrai projet, tu as des dizaines de classes, plus celles de bibliothèques tierces. Tôt ou tard, deux Client existent (le tien et celui d'une librairie). Sans organisation, c'est la collision de noms : PHP ne sait plus de laquelle tu parles.

Les namespaces (espaces de noms) règlent ça : ils rangent les classes dans des « dossiers logiques ». Boutique\Client et Facturation\Client cohabitent sans conflit.

Déclarer et utiliser un namespace

Prédisez avant de lire

Deux bibliothèques définissent chacune une classe nommée Logger : App\Logger et Monolog\Logger. Sans namespace, déclarer deux classes Logger provoquerait une erreur fatale. Avant de dérouler : pourquoi PHP ne les confond-il pas quand elles sont dans des namespaces différents, et à quoi sert use App\Logger; en haut d'un fichier ?

Voir la réponse

Le namespace fait partie du nom complet de la classe : App\Logger et Monolog\Logger sont deux noms distincts pour PHP, donc aucune collision. Pour référencer précisément l'une ou l'autre, on utilise le nom pleinement qualifié (\App\Logger, \Monolog\Logger) ou on importe avec use App\Logger; en tête de fichier, ce qui permet ensuite d'écrire juste Logger (PHP résout vers App\Logger). Si on a besoin des deux en même temps, on alias : use Monolog\Logger as MonoLogger;. C'est ce mécanisme qui sous-tend l'autoloading PSR-4 : le nom qualifié se traduit directement en chemin de fichier.

// fichier src/Boutique/Produit.php
namespace Boutique;

class Produit {
    public function __construct(public string $nom) {}
}
// ailleurs, pour s'en servir :
use Boutique\Produit;        // on "importe" le nom

$p = new Produit("Café");    // au lieu de new \Boutique\Produit("Café")

Convention : le namespace reflète l'arborescence des dossiers (Boutique\Produitsrc/Boutique/Produit.php). C'est la base de l'autoloading.

L'autoloading : charger les classes toutes seules

Sans autoloading, il faudrait un require manuel pour chaque fichier de classe : ingérable. L'autoloading charge le bon fichier automatiquement la première fois qu'une classe est utilisée, en se basant sur son namespace.

Le standard s'appelle PSR-4, et l'outil universel, c'est Composer (le gestionnaire de dépendances de PHP). En pratique :

// composer.json : on mappe un préfixe de namespace à un dossier
{
    "autoload": {
        "psr-4": { "App\\": "src/" }
    }
}

// puis, une seule ligne en tête du projet :
require 'vendor/autoload.php';

// et c'est tout : new App\Boutique\Produit() charge src/Boutique/Produit.php tout seul

Mais Composer ne se contente pas de ranger TES classes : c'est aussi lui qui installe les bibliothèques tierces. Une commande suffit :

composer require monolog/monolog

Elle télécharge le paquet dans vendor/, l'inscrit dans composer.json et le branche sur l'autoloader. Ses classes deviennent utilisables aussitôt, sans aucun require manuel :

use Monolog\Logger;

$log = new Logger('app');   // classe chargée automatiquement depuis vendor/
$log->warning('Attention !');

C'est la même mécanique PSR-4, appliquée cette fois au code des autres. Et comme composer.json et composer.lock sont versionnés, toute l'équipe réinstalle exactement les mêmes versions avec un simple composer install.

Tu n'apprends pas Composer par cœur : retiens la logique. Un namespace = un chemin de dossier, et l'autoloader traduit le nom de la classe en chemin de fichier. Si tu comprends ça, tu sauras toujours où ranger (et retrouver) une classe.

Exécute : deux namespaces, zéro collision

Ici, deux classes pourraient s'appeler pareil : leur namespace les distingue. (On utilise la syntaxe à blocs pour tout mettre dans un seul fichier exécutable.)

<?php
namespace Boutique {
    class Client { public function bonjour(): string { return "Client de la boutique"; } }
}
namespace Facturation {
    class Client { public function bonjour(): string { return "Client de la facturation"; } }
}
namespace {  // espace global
    $a = new \Boutique\Client();
    $b = new \Facturation\Client();
    echo $a->bonjour() . "\n";   // Client de la boutique
    echo $b->bonjour() . "\n";   // Client de la facturation
    echo get_class($b) . "\n";  // Facturation\Client
}
?>

The problem: too many classes, names clashing

In a real project, you have dozens of classes, plus third-party libraries. Sooner or later, two Client classes exist (yours and a library's). Without organization, that's a name collision: PHP no longer knows which one you mean.

Namespaces fix this: they file classes into "logical folders". Boutique\Client and Facturation\Client coexist without conflict.

Declaring and using a namespace

Predict before reading

Two libraries each define a class named Logger: App\Logger and Monolog\Logger. Without namespaces, declaring two Logger classes would cause a fatal error. Before scrolling down: why doesn't PHP confuse them when they live in different namespaces, and what does use App\Logger; at the top of a file actually do?

See the answer

The namespace is part of the class's fully qualified name: App\Logger and Monolog\Logger are two distinct names as far as PHP is concerned, so there is no collision. To reference one specifically, you use the fully qualified name (\App\Logger, \Monolog\Logger) or import with use App\Logger; at the top of the file — which then lets you write just Logger (PHP resolves it to App\Logger). If you need both at once, alias one: use Monolog\Logger as MonoLogger;. This mechanism also underpins PSR-4 autoloading: the qualified name maps directly to a file path.

// file src/Boutique/Produit.php
namespace Boutique;

class Produit {
    public function __construct(public string $nom) {}
}
// elsewhere, to use it:
use Boutique\Produit;        // we "import" the name

$p = new Produit("Coffee");  // instead of new \Boutique\Produit("Coffee")

Convention: the namespace mirrors the folder tree (Boutique\Produitsrc/Boutique/Produit.php). That's the basis of autoloading.

Autoloading: loading classes automatically

Without autoloading, you'd need a manual require for each class file — unmanageable. Autoloading loads the right file automatically the first time a class is used, based on its namespace.

The standard is called PSR-4, and the universal tool is Composer (PHP's dependency manager). In practice:

// composer.json: map a namespace prefix to a folder
{
    "autoload": {
        "psr-4": { "App\\": "src/" }
    }
}

// then, a single line at the top of the project:
require 'vendor/autoload.php';

// and that's it: new App\Boutique\Produit() loads src/Boutique/Produit.php by itself

But Composer doesn't just organize YOUR classes: it's also how you install third-party libraries. One command is enough:

composer require monolog/monolog

It downloads the package into vendor/, records it in composer.json and wires it into the autoloader. Its classes become usable right away, with no manual require:

use Monolog\Logger;

$log = new Logger('app');   // class loaded automatically from vendor/
$log->warning('Watch out!');

It's the same PSR-4 machinery, this time applied to other people's code. And since composer.json and composer.lock are versioned, the whole team reinstalls the exact same versions with a simple composer install.

You don't learn Composer by heart: remember the logic. A namespace = a folder path, and the autoloader translates the class name into a file path. Understand that, and you'll always know where to put (and find) a class.

Run it: two namespaces, zero collision

Here, two classes could have the same name: their namespace tells them apart. (We use the block syntax to fit everything in one runnable file.)

<?php
namespace Boutique {
    class Client { public function bonjour(): string { return "Shop client"; } }
}
namespace Facturation {
    class Client { public function bonjour(): string { return "Billing client"; } }
}
namespace {  // global space
    $a = new \Boutique\Client();
    $b = new \Facturation\Client();
    echo $a->bonjour() . "\n";   // Shop client
    echo $b->bonjour() . "\n";   // Billing client
    echo get_class($b) . "\n";  // Facturation\Client
}
?>

🎯 Pratique

S'entraîner (clique pour ouvrir) :

🧠 Rappel libre
Rappel libre

Sans remonter dans la leçon : à quoi sert un namespace, et quelle est la règle PSR-4 qui lie App\Boutique\Produit à un fichier sur le disque ?

Un namespace range les classes dans des « dossiers logiques » pour éviter les collisions de noms (deux Client peuvent coexister). En PSR-4, le namespace reflète l'arborescence : avec le mapping "App\\": "src/", la classe App\Boutique\Produit est chargée depuis src/Boutique/Produit.php. L'autoloader traduit le nom complet en chemin de fichier.
⚖️ Juge le code de l'IA
Accepter ou rejeter le code de l'IA

Ton composer.json mappe "App\\": "src/". L'IA te donne ce fichier de classe. Ton rôle de relecteur : l'accepter tel quel ou le rejeter, et dire pourquoi.

// fichier : src/Boutique/Produit.php
namespace App\Models;

class Produit {
    public function __construct(public string $nom) {}
}
Rejeter. Le namespace App\Models ne correspond pas au chemin src/Boutique/ : PSR-4 attend la classe App\Models\Produit dans src/Models/Produit.php. Avec ce mapping, l'autoloader cherchera au mauvais endroit et lèvera une « class not found ». Le code compile en isolé, mais il casse dès que Composer essaie de le charger. Corriger en namespace App\Boutique; (ou déplacer le fichier dans src/Models/).
À quoi servent les namespaces ?
Que fait l'autoloading (PSR-4 / Composer) ?
Deux bibliothèques définissent chacune une classe Logger : App\Logger et Monolog\Logger. Pourquoi PHP ne les confond-il pas ?
Ton composer.json contient "App\\": "src/". Tu écris use App\Boutique\Produit; puis new Produit(). Que se passe-t-il la première fois que cette classe est utilisée ?
Prochaine étape

Tu sais désormais structurer un vrai projet PHP objet : classes, visibilité, héritage, interfaces, traits et namespaces. Le même état d'esprit existe côté navigateur : direction JavaScript avancé, avec ses classes, ses modules et les API du navigateur.

JavaScript avancé →

Une erreur dans cette leçon, un passage flou, une question ? Écrivez-moi : chaque retour améliore ce cours.

Besoin d'un développeur pour votre projet ?

Réponse sous 24h · Sans engagement