Les espaces de noms

Résumé Support Quiz

Dans ce chapitre, nous allons découvrir le principe des espaces de noms, ou namespace, en PHP. L'objectif est de comprendre pourquoi ils existent, comment les déclarer et comment utiliser use pour importer des classes plus simplement.

Les namespaces deviennent surtout utiles quand une application grandit. Plus le projet contient de classes, plus le risque d'avoir deux classes avec le même nom augmente.

Le problème des noms de classes

Imaginons une classe Message utilisée pour représenter un message dans un livre d'or. Plus tard, on ajoute un formulaire de contact, et on crée aussi une classe Message pour représenter un message de contact.

On se retrouve alors avec deux problèmes :

  • quand on lit le code, on ne sait plus forcément de quelle classe Message on parle.
  • si on charge les deux classes en même temps, PHP ne peut pas déclarer deux classes avec le même nom.

Pendant longtemps, une solution consistait à ajouter des préfixes dans les noms de classes, par exemple GrafikartGuestbookMessage. Cela permettait d'éviter les conflits, mais les noms devenaient rapidement longs et peu pratiques à manipuler.

Les namespaces permettent de résoudre ce problème plus proprement.

Déclarer un namespace

Un namespace permet de ranger une classe dans une sorte de dossier virtuel. On le déclare en haut du fichier avec le mot-clé namespace.

namespace Grafikart\Guestbook; class Message { }

Ici, la classe ne s'appelle plus simplement Message dans l'espace global. Son nom complet devient :

Grafikart\Guestbook\Message

On peut organiser les classes selon leur rôle. Par exemple, les exceptions peuvent être placées dans un namespace dédié :

namespace Grafikart\Exceptions;

Et si besoin, on peut aller plus loin avec des sous-namespaces, comme Grafikart\Exceptions\Http.

Utiliser une classe avec son nom complet

Une fois une classe placée dans un namespace, il faut préciser ce namespace lorsqu'on veut l'utiliser depuis un autre fichier.

$message = new \Grafikart\Guestbook\Message();

L'antislash au début indique que l'on part de la racine des namespaces. Cette syntaxe fonctionne, mais elle devient vite lourde si on doit l'écrire partout.

Attention aux classes natives PHP

Quand on déclare un namespace dans un fichier, les classes utilisées ensuite sont recherchées dans ce namespace par défaut.

Par exemple, si on écrit DateTime dans une classe située dans Grafikart\Guestbook, PHP va d'abord chercher :

Grafikart\Guestbook\DateTime

Or DateTime est une classe native de PHP située dans l'espace de nom racine. Pour l'utiliser directement, on peut préfixer le nom avec un antislash :

$date = new \DateTime();

Mais là encore, ce n'est pas forcément agréable à répéter.

Importer une classe avec use

Pour éviter d'écrire le nom complet à chaque fois, on utilise use en haut du fichier.

namespace Grafikart\Guestbook; use DateTime; use DateTimeZone; class Message { public function getDate(): DateTime { return new DateTime('now', new DateTimeZone('Europe/Paris')); } }

use DateTime indique que lorsqu'on écrit DateTime, on parle de la classe DateTime qui se trouve dans le namespace racine.

Le même principe fonctionne avec nos propres classes.

use Grafikart\Guestbook\Message; $message = new Message();

Cela permet de garder un code plus lisible. En plus, les éditeurs modernes savent souvent ajouter automatiquement les imports quand on utilise une classe.

Placer plusieurs classes dans le même namespace

Si deux classes appartiennent au même domaine, on peut les placer dans le même namespace. Par exemple, une classe Guestbook et une classe Message peuvent toutes les deux appartenir à Grafikart\Guestbook.

namespace Grafikart\Guestbook; class Guestbook { public function addMessage(Message $message): void { // ... } }

Dans ce cas, comme Message est dans le même namespace que Guestbook, PHP sait où chercher la classe. Il n'est pas nécessaire d'ajouter un use pour cette classe.

En revanche, depuis un fichier comme index.php, il faudra importer les classes utilisées :

use Grafikart\Guestbook\Guestbook; use Grafikart\Guestbook\Message;

Gérer les conflits avec les alias

Les namespaces permettent d'avoir plusieurs classes avec le même nom tant qu'elles ne sont pas dans le même espace de nom.

On peut donc avoir :

Grafikart\Guestbook\Message Grafikart\Contact\Message

Le problème revient si on veut importer les deux classes avec use, car elles auraient toutes les deux le même nom court Message. Pour résoudre ça, on peut utiliser un alias avec as.

use Grafikart\Guestbook\Message; use Grafikart\Contact\Message as ContactMessage; $message = new Message(); $contactMessage = new ContactMessage();

L'alias permet de renommer une classe au moment de l'import et d'éviter les conflits dans le fichier courant.

Grouper plusieurs imports

Quand plusieurs classes viennent du même namespace, PHP permet de grouper les imports avec des accolades.

use Grafikart\Guestbook\{Guestbook, Message};

Cette écriture revient au même que :

use Grafikart\Guestbook\Guestbook; use Grafikart\Guestbook\Message;

Elle évite simplement de répéter plusieurs fois le même préfixe.

Où utiliser les namespaces ?

Les namespaces peuvent s'appliquer aux classes, mais aussi aux fonctions et aux constantes. Dans la pratique présentée ici, on les utilise surtout pour organiser les classes.

Le bénéfice principal est que le début d'un fichier indique clairement quelles classes sont utilisées grâce aux imports use. Cela aide à mieux comprendre l'origine des objets manipulés et à mieux organiser son projet.

Il reste une limite : on doit encore faire les require pour charger les fichiers, en plus des imports. La suite logique est donc de mettre en place un chargement automatique des classes. C'est ce qui sera abordé ensuite avec Composer.

Ressources