Présentation des espaces de noms
Les espaces de nom en PHP sont des sortes de dossiers virtuels qui vont nous servir à encapsuler (c’est-à-dire à isoler) certains éléments de certains autres.
Les espaces de noms vont notamment permettre d’éliminer les conflits possibles entre deux éléments de même nom. Cette ambiguïté autour du nom de plusieurs éléments de même type peut survenir lorsqu’on a défini des fonctions, classes ou constantes personnalisées et qu’on fait appel à des extensions ou des bibliothèques externes PHP.
Ici, vous devez savoir qu’une extension ou une bibliothèque externe est un ensemble de code qui ne fait pas partie du langage nativement mais qui a pour but de rajouter des fonctionnalités au langage de base en proposant notamment par exemple des classes préconstruites pour créer une connexion à une base de données ou pour filtrer des données externes.
Il est possible que certaines classes, fonctions ou constantes d’une extension qu’on va utiliser dans un script possèdent des noms identiques à des classes, fonctions ou constantes personnalisées qu’on a défini dans un script.
Sans définition d’un espace de noms, cela va évidemment créer des conflits, puisque le reste du script utilisant la fonction, classe ou constante ne va pas savoir à laquelle se référer.
Pour prendre un exemple concret, vous pouvez considérer que les espaces de noms fonctionnent comme les dossiers sur notre ordinateur. Alors qu’il est impossible de stocker deux fichiers de même nom dans un même dossier, on va tout à fait pouvoir stocker deux fichiers de même nom dans deux dossiers différents. En effet, dans ce dernier cas, il n’y a plus d’ambiguïté puisque les deux fichiers ont un chemin d’accès et de fait une adresse différente sur notre ordinateur.
Définir un espace de noms simple
Pour définir un espace de noms, on va utiliser le mot clef namespace
suivi de notre espace de noms.
Notez déjà que les noms d’espaces de noms ne sont pas sensibles à la casse et qu’on ne va pas pouvoir définir un espace de noms avec un nom commençant par « PHP ».
Notez également que seuls les classes, les traits, les interfaces, les fonctions et les constantes vont être affectés par un espace de noms c’est-à-dire vont pouvoir effectivement être différenciés du reste du code grâce à l’espace de noms.
On va pouvoir placer d’autres types d’éléments comme des variables dans un espace de noms mais ces éléments ne seront pas affectés par l’espace de noms.
Par ailleurs, vous devez également savoir qu’un espace de noms doit être déclaré avant tout autre code dans un fichier à l’exception de la commande declare
qui peut être déclarée avant.
Ici, on crée un premier espace de noms simple qu’on appelle Exemple
dans un fichier séparé. J’enregistre mon fichier sous le nom exemple.namespace.php
. Ensuite, on définit différents éléments dans notre espace de noms.
Notez qu’il existe deux syntaxes pour la déclaration d’un espace de noms : une syntaxe utilisant un point-virgule de type namespace MonEspaceDeNoms ;
et une syntaxe utilisant plutôt un couple de parenthèses comme ci-dessus.
Personnellement, je vous conseille la syntaxe avec les parenthèses qui est plus claire et qui fonctionnent dans toutes les situations au contraire de celle avec le point-virgule.
Notez ici qu’aucun autre code PHP ne va pouvoir être défini en dehors d’un espace de noms. Si on souhaite créer du code « global » (du code en dehors d’un espace de noms défini), il faudra déclarer un espace de noms sans nom, en utilisant simplement le mot clef namespace
.
Finalement, notez également qu’on va pouvoir définir et utiliser le même espace de noms dans plusieurs fichiers ce qui va être très utile pour scinder le contenu d’un espace de noms entre plusieurs fichiers.
On va également en théorie pouvoir définir plusieurs espaces de noms dans un même fichier mais cela est considéré comme une mauvaise pratique et donc on essaiera tant que possible de ne pas faire cela en pratique.
Définir un sous espace de noms
De la même façon qu’avec nos dossiers réels d’ordinateur, nous allons pouvoir définir des niveaux de hiérarchie d’espaces de noms et ainsi créer des sous espaces de noms.
Pour cela, on va préciser les différents noms liés aux niveaux et séparés par des antislashs.
Ici, j’enregistre mon sous espace de noms dans un nouveau fichier que j’appelle sousexemple.namespace.php
. Mis à part la relation hiérarchique entre nos deux espaces, ceux-ci sont complètement différenciés et vont pouvoir contenir les éléments qu’ils souhaitent.
Accéder aux éléments d’un espace de noms
Pour utiliser des éléments d’un espace de noms en particulier, il va falloir que PHP sache à quel espace de noms on fait référence. Pour cela, des règles similaires à la recherche d’un fichier sur notre ordinateur sont utilisées en PHP.
Pour accéder à un élément d’un espace de noms, on peut déjà préciser un nom non qualifié, c’est-à-dire ne préciser que le nom de l’élément en question.
Si on précise le nom d’un élément sans qualificatif (c’est-à-dire sans préfixe) dans un espace de noms nommé, alors c’est l’élément de même nom dans l’espace nommé qui sera utilisé.
Si on précise le nom d’un élément sans qualificatif depuis l’espace global, alors c’est l’élément de même nom dans l’espace global qui sera utilisé.
Attention ici : dans le cas où on souhaite utiliser une fonction ou une constante avec un nom sans qualificatif depuis un espace de noms nommé et que la fonction ou la constante en question n’est pas trouvée dans l’espace, alors une fonction / constante du même nom sera cherchée dans l’espace global. Ce ne sera pas le cas pour une classe.
On peut également utiliser un nom qualifié pour utiliser un élément d’un espace de noms. Le nom qualifié correspond au nom de l’élément préfixé par son chemin d’accès à partir de l’endroit où il est appelé (c’est-à-dire le nom de l’élément + le nom des sous espaces de noms séparés par des antislashs).
Si on utilise l’écriture sous\bonjour()
depuis notre espace de noms Exemple
, par exemple, on indique qu’on souhaite accéder à la fonction bonjour()
située dans exemple\sous\bonjour()
.
Finalement, on peut encore préciser un nom absolu pour accéder à un élément d’un espace de noms. Un nom absolu correspond au chemin complet de l’élément, c’est-à-dire au nom de l’élément préfixé de tous les espaces et sous espaces et commençant avec un antislash.
<?php namespace Exemple{ //On inclut notre espace de noms exemple\sous include 'sousexemple.namespace.php'; class Utilisateur{ /*Code de la classe*/ }; const VILLE = 'Toulon'; function bonjour() { echo 'Bonjour<br>'; }; $cp = 83000; bonjour(); sous\bonjour(); \exemple\sous\bonjour(); } namespace{ //Code global } ?>
<!DOCTYPE html> <html> <head> <title>Cours PHP & MySQL</title> <meta charset="utf-8"> <link rel="stylesheet" href="cours.css"> </head> <body> <h1>Titre principal</h1> <?php include 'exemple.namespace.php'; ?> <p>Un paragraphe</p> </body> </html>
La commande namespace et la constante magique __NAMESPACE__
La constante magique __NAMESPACE__
contient le nom de l’espace de noms courant sous forme de chaine de caractères. Dans le cas où on l’appelle depuis l’espace global, elle contient une chaine vide.
On va pouvoir utiliser cette constante pour récupérer le nom de l’espace de noms courant et accéder à ses éléments ou à d’autres éléments en partant de ce nom dans des situations où on n’a pas accès directement au nom.
La commande namespace
va représenter l’espace de noms courant. C’est l’équivalent de l’opérateur self
des classes vu précédemment mais pour les espaces de noms.
On va donc également pouvoir s’en servir pour accéder à des éléments d’un espace de noms en représentant cet espace à l’aide de la commande namespace
.
<?php namespace Exemple{ //On inclut notre espace de noms exemple\sous include 'sousexemple.namespace.php'; class Utilisateur{ /*Code de la classe*/ }; const VILLE = 'Toulon'; function bonjour() { echo 'Bonjour<br>'; }; $cp = 83000; bonjour(); sous\bonjour(); \exemple\sous\bonjour(); namespace\bonjour(); echo 'Namespace : ' .__NAMESPACE__. '<br>'; } namespace{ echo 'Namespace : ' .__NAMESPACE__. '<br>'; } ?>
<!DOCTYPE html> <html> <head> <title>Cours PHP & MySQL</title> <meta charset="utf-8"> <link rel="stylesheet" href="cours.css"> </head> <body> <h1>Titre principal</h1> <?php include 'exemple.namespace.php'; ?> <p>Un paragraphe</p> </body> </html>
Accéder à un élément du contexte global depuis un espace de noms
Lorsqu’on ne définit pas d’espace de noms, les éléments (classes, fonctions, etc.) sont automatiquement placés dans l’espace de noms global.
Pour accéder à un élément de l’espace global depuis un espace de noms, on peut préfixer le nom de l’élément avec un simple antislash.
<?php namespace Exemple{ //On inclut notre espace de noms exemple\sous include 'sousexemple.namespace.php'; class Utilisateur{ /*Code de la classe*/ }; const VILLE = 'Toulon'; function bonjour() { echo 'Bonjour<br>'; }; $cp = 83000; bonjour(); \bonjour(); } namespace{ function bonjour(){ echo 'Bonjour depuis l\'espace global'; } } ?>
Importation (des éléments) d’un espace de noms et création d’alias
Créer un « alias » en PHP correspond à définir un autre nom pour désigner un élément déjà existant dans notre script.
Pour importer un élément d’un espace de noms, nous allons utiliser l’instruction use
qu’on a déjà eu l’occasion de rencontrer dans la leçon relative aux traits.
Cette instruction, en important un élément d’un espace de noms, va également automatiquement créer un alias en utilisant le nom en soi de l’élément. On va cependant également pouvoir définir un alias personnalisé avec le mot clef as
.
Notez qu’avant la version 5.6 de PHP, nous ne pouvions importer et définir d’alias que pour un nom de classe, un nom d’interface et pour un espace de noms en soi.
Depuis PHP 5.6, on peut également importer et créer un alias personnalisé pour une fonction et importer une constante.
Notez également que depuis PHP 7.0, les classes, fonctions et constantes importées depuis le même espace de noms peuvent être regroupées dans une seule instruction use
.
Enfin, lorsqu’on précise un nom absolu lors d’une importation avec use
, il faut savoir qu’il est recommandé d’omettre l’antislash initial dans le chemin du fichier.
Les exemples ci-dessous illustrent comment importer et créer des alias des différents éléments d’un espace de noms.
<?php namespace Exemple\Sous{ class Utilisateur{ /*Code de la classe*/ }; const VILLE = 'Lyon'; function bonjour() { echo 'Salut<br>'; } function bonsoir() { echo 'Bonsoir<br>'; } function bonne_nuit() { echo 'Bonne nuit<br>'; } $cp = 69000; } ?>
<?php namespace Exemple{ //On inclut notre espace de noms exemple\sous include 'sousexemple.namespace.php'; class Utilisateur{ /*Code de la classe*/ }; const VILLE = 'Toulon'; function bonjour() { echo 'Bonjour<br>'; }; $cp = 83000; use Exemple\Sous; //Revient à écrire use Exemple\Sous as Sous use Exemple\Sous\Utilisateur as Sousutil; //Alias d'une classe use function Exemple\Sous\bonjour as bjr; //Alias d'une fonction use const Exemple\Sous\VILLE; //Importation d'une constante //Import et alias de plusieurs fonctions avec une instruction use use function Exemple\Sous\{bonsoir as bns, bonne_nuit as nuit}; var_dump($obj = new Sousutil); echo '<br>'; bjr(); echo VILLE; echo '<br>'; bns(); nuit(); } namespace{ function bonjour(){ echo 'Bonjour depuis l\'espace global'; } } ?>
Notez finalement que dans le cas d’une inclusion de fichiers, les fichiers inclus n’hériteront pas des règles d’importation du fichier parent puisque ces règles ne concernent que le fichier dans lequel elles ont été définies.