Namespace ========= Pourquoi avons-nous besoin d'espaces de noms ? -------------------------------------------------- Comme la taille de votre bibliothèque de code PHP augmente, il existe un risque accru de redéfinition accidentelle d'une fonction ou d'un nom de classe qui a été déclaré auparavant. Le problème est exacerbant lorsque vous tentez d'ajouter des composants tiers ou plugins. Que se passe-t-il si vous instaurez une classe Database ou User qui existe déjà ? Jusqu'à présent, la seule solution a été d'utiliser des noms de fonctions longs. Par exemple, WordPress préfixe chaque nom avec **"wp\_ "**. Le Zend Framework utilisais une convention de nommage très descriptif afin de donner des noms de classes longs comme la classe **Zend\_Search\_Lucene\_Analysis\_Analyzer\_Common\_Text\_CaseInsensitive**. Les problèmes de collision de noms peuvent être résolus avec les espaces de noms. Les constantes PHP, classes et fonctions peuvent être regroupées en bibliothèques d'espace de noms. Comment définir les espaces de noms ? -------------------------------------- Par défaut, toutes les constantes, les classes, et les noms de fonction sont placés dans l'espace global - comme elles l'étaient avant que PHP supporte les espaces de noms. Le code des espaces de noms est défini en utilisant un mot-clé namespace unique en haut de votre fichier PHP. Ce doit être la première commande (à l'exception de declare) et pas de code non-PHP, HTML, ou d'espaces blancs ne peuvent précéder la commande, par exemple. .. code-block:: php Bien que cela soit possible, je le déconseille : conserver votre santé mentale en définissant un seul espace de noms par fichier. Sous-espaces de noms --------------------------- PHP vous permet de définir une hiérarchie d'espaces de noms afin de subdiviser vos bibliothèques. Les sous-espaces de noms sont séparés par une barre oblique inverse (\\), par exemple : - MonProjet \\ Nom - MonProjet \\ Database \\ MySQL - NomEntreprise \\ MonProjet \\ Bibliothèque \\ FichiersCommuns \\ widget1 Appeler du code des espaces de noms ----------------------------------- Dans un fichier nommé lib1.php, nous allons définir une constante, une fonction et une classe au sein de l'espace de noms App \\ LIB1 : .. code-block:: php Nous pouvons maintenant inclure ce code dans un autre fichier PHP, parexemple : .. code-block:: php Aucun espace de noms n'est défini dans myapp.php afin que le code existe dans l'espace global. Toute référence directe à MYCONST, MyFunction ou MyClass va échouer parce qu'elles existent dans l'espace de noms App \\ LIB1. Pour appeler du code dans lib1.php, on peut ajouter un préfixe \\ App \\ LIB1 pour définir des noms pleinement qualifiés. Le résultat suivant est émis quand on charge myapp.php : .. code-block:: php App\Lib1\MYCONST App\Lib1\MyFunction App\Lib1\MyClass::WhoAmI Les noms pleinement qualifiés peuvent devenir assez longs et il y a peu d'avantages évidents par rapport à la définition des noms de classe longs tels que App-LIB1-MyClass. Par conséquent, dans le prochain article, nous allons discuter du cumul et jeter un oeil de plus près sur le fonctionnement de PHP quant à la résolution des noms d'espace de noms. A titre d'exemple, nous allons définir deux blocs de code presque identique, la seule différence est leur espace de noms : .. code-block:: php .. code-block:: php Il y a un peu de terminologie PHP à comprendre avant de commencer... Nom pleinement qualifié ----------------------- Tout code PHP peut se référer à un nom pleinement qualifié - un identifiant commençant l'espace de noms et par le séparateur de barre oblique inverse - par exemple **\\App\\LIB1\\MYCONST**, **\\App\\LIB2\\MyFunction()**, etc. Les noms pleinement qualifiés n'ont pas d'ambiguïté. La première barre oblique inverse fonctionne de manière semblable à un chemin de fichier, il signifie l'espace global du «root». Si nous avons implémenté une fonction **MyFunction()** différente dans notre espace global, elle pourrait être appelée à partir de lib1.php ou lib2.php en utilisant **\\MyFunction()**. Les noms pleinement qualifiés sont utiles pour des appels uniques de fonctions ou d'initialisation objet. Toutefois, ils peuvent devenir impraticables lorsque vous faites beaucoup d'appels. Comme nous allons le découvrir, PHP offre d'autres options pour nous sauver des crampes de frappe des espaces de nommage. Nom qualifié ------------ Un identifiant avec au moins un séparateur d'espace de noms, par exemple **LIB1\\MyFunction()**. Nom non qualifié ---------------- Un identifiant, sans séparateur d'espace de noms, par exemple **MyFunction()**. Travail au sein du même espace de noms -------------------------------------- Considérons le code suivant : .. code-block:: php Même si l'on inclut à la fois **lib1.php** et **lib2.php**, les identificateurs **MYCONST**, **MyFunction**, et **MyClass** référencent seulement le code dans **lib1.php**. Cela se produit parce que le code **myapp1.php** est dans le même espace de noms **\\LIB1** : Résultat : .. code-block:: php App\Lib1\MYCONST App\Lib1\MyFunction App\Lib1\MyClass::WhoAmI Importation d'espace de noms ------------------------------ Les espaces de noms peuvent être importés grâce à l'opérateur **use**, par exemple : .. code-block:: php | Vous pouvez définir autant de use que voulu ou vous pouvez séparer les espaces de noms par une virgule. | Dans cet exemple, nous avons importé l'espace de noms **App\\LIB2**. Nous ne pouvons toujours pas faire référence directement à **MYCONST**, **MyFunction** ou **MyClass** parce que notre code se trouve dans l'espace global, et PHP va les chercher là-bas. Toutefois, si l'on ajoute un préfixe de **LIB2\\**, ils deviennent des noms qualifiés. | PHP va chercher dans les espaces de noms importés jusqu'à ce qu'il trouve une correspondance. Résultat : .. code-block:: php App\Lib2\MYCONST App\Lib2\MyFunction App\Lib2\MyClass::WhoAmI Les alias d'espace de noms ---------------------------- Les alias d'espace de noms sont peut-être les implémentations les plus utiles. Les alias nous permettent de référencer les espaces de noms en utilisant un nom plus court. .. code-block:: php La première déclaration de use définit **App\\LIB1** comme « **L** ». Les noms qualifiés utilisant des «\ **L** » seront traduits par **App\\LIB1** au moment de la compilation. On peut donc se référer à **L\\MYCONST** et **L\\MyFunction()** plutôt qu'à leurs noms pleinement qualifiés. La seconde déclaration de **use** est plus intéressante. Elle définit '**obj**\ ' comme alias pour la classe **MyClass** au sein de l'espace de noms **App\\Lib2\\**. Cela n'est possible que pour les classes, pas pour des constantes ou des fonctions. Nous pouvons maintenant utiliser **new Obj()** ou exécuter des méthodes statiques, comme indiqué ci-dessus. Résultat .. code-block:: php App\Lib1\MYCONST App\Lib1\MyFunction App\Lib1\MyClass::WhoAmI App\Lib2\MyClass::WhoAmI Les règles de résolution de noms en PHP ------------------------------------------ Les noms d'identifiants en PHP sont résolus en utilisant les règles d'espace de noms suivant. Reportez-vous au `manuel PHP `_ pour plus d'information. #. Les appels à des fonctions pleinement qualifiées, des classes ou des constantes sont résolues au moment de la compilation. #. Les noms qualifiés ou non sont convertis selon les règles d'importation, par exemple si le nom A\\B\\C est importé en tant que C, un appel à C\\D\\e() est traduit en A\\B\\C\\D\\e(). #. L'intérieur d'un espace de noms, tous les noms qualifiés qui ne sont pas déjà convertis selon les règles d'importation ont l'espace de noms courant préfixé, par exemple si un appel à C\\D\\e() est effectué au sein de l'espace de noms A\\B, il est traduit à A\\B\\C\\D\\e(). #. Les noms de classes non qualifiées sont traduits selon les règles actuelles d'importation et le nom complet est remplacé par le nom importé court, par exemple si la classe C dans un espace de noms \\B est importée sous X, new X() est traduit en new A\\B\\C(). #. Les appels de fonctions non qualifiées au sein d'un espace de noms sont résolus au moment de l'exécution. Par exemple, si MyFunction() est appelée dans l'espace de noms A\\B, PHP cherche d'abord la fonction \\A\\B\\MyFunction(). Si elle n'est pas trouvée, il cherche \\MyFunction() dans l'espace global. #. Les appels à des noms de classes non qualifiés ou qualifiés sont résolus au moment de l'exécution. Par exemple, si nous appelons new C() au sein de l'espace de noms A\\B, PHP va chercher la classe A\\B\\C. Si elle n'est pas trouvée, il va tenter de charger automatiquement A\\B\\C. La constante _NAMESPACE_ ------------------------- **_NAMESPACE_** est une chaîne PHP qui retourne toujours le nom de l'espace de noms courant. Dans l'espace global, elle renverra une chaîne vide. .. code-block:: php La valeur présente des avantages évidents durant le débogage. Elle peut également être utilisée pour générer dynamiquement un nom de classe entièrement qualifié, par exemple : .. code-block:: php WhoAmI(); // sortie : App\Lib1\MyClass::WhoAmI ?> Le mot clé namespace --------------------- Le mot clé **namespace** peut être utilisé pour référencer explicitement un élément dans l'espace de nom courant ou un sous-espace de noms. C'est l'équivalent dans les espaces de noms de **self** au sein des classes : .. code-block:: php WhoAmI(); // sortie : App\Lib1\MyClass::WhoAmI ?> Autoloading des classes d'un espace de noms -------------------------------------------- L'un des meilleurs moyens de gagner du temps avec PHP 5 est l'autoloading. À l'échelle globale (non-espace de noms) du code PHP, une fonction de chargement automatique standard pourrait être écrite comme ceci : .. code-block:: php En PHP 5.3, vous pouvez créer une instance d'une classe d'espace de noms. Dans cette situation, l'espace de noms entièrement qualifié et le nom de classe sont passés à la fonction **\_\_autoload()**, par exemple la valeur de **$class\_name** pourrait être **App\\LIB1\\MyClass**. Vous pouvez continuer à mettre tous vos fichiers de classe PHP dans le même dossier et y chainer l'espace de nom, cependant, cela pourrait entraîner des conflits de nom de fichier. Alternativement, la hiérarchie de vos fichiers de classes pourraient être organisée de la même manière que la structure de votre espace de noms. Par exemple, un fichier **MyClass.php** pourrait être créé dans le dossier **/classes/App/Lib1** : .. code-block:: php Un fichier dans le dossier racine pourrait alors utiliser le code suivant : .. code-block:: php WhoAmI(); // autoload function function __autoload($class) { // convert namespace to full file path $class = 'classes/' . str_replace('\\', '/', $class) . '.php'; require_once($class); } ?> Explications : - La classe **\\LIB1\\MyClass** est aliassée en tant que **MC**. - **new MC()** est traduit par **new App\\Lib1\\MyClass()** pendant la compilation. - La chaîne **App\\LIB1\\MyClass** est passé à la fonction **\_\_autoload**. Cela remplace tous les antislash de l'espace de noms avec le chemin du fichier avant le slash, et modifie la chaîne si le fichier **classes\\App\\LIB1\\ MyClass.php** est chargé.