Integration of PHP Namespaces » History » Version 2

« Previous - Version 2/3 (diff) - Next » - Current version
remi, 10/01/2013 06:21 PM


Utilisation des espaces de nom (GLPI >= 5.3)

Les espaces de nom PHP permettent de regrouper des classes dans une même entitée. Ils évitent de "polluer" l'espace de nom global par des éléments appartenant à des composants bien délimités. Par exemple, les composants extérieurs (Zend, ezComponent, ...) contiennent des classes dont les noms pourraient entrer en conflit avec ceux de GLPI. D'une autre côté, la classe HTMLTable_ contient un certain nombre de sous-composants (Table, Row, Cell, Header, ...) qui n'intéressent que la classe HTMLTable_. En d'autres termes, que ce soit pour les classes des composants extérieurs comme celles de composants interne, il s'agit de "détails d'implémentation" qui n'ont aucune signification hors du contexte spécifique du package.

Dans le cadre de GLPI, nous pourrions les utiliser pour créer des "packages" homogènes. Par exemple, nous pourrions avoir un "package" OCS qui regrouperait toutes les classes gérant l'interface avec OCS. Un autre package intéressant serait HTMLTable, dont le but est de gérer des tableaux HTML automatiquement.
Comme le suggère Moyo (dans AutoLoad), un namespace Plugin prendrait en charge tous les plugins.

Utilisation d'un espace de nom dans PHP

Pour créer l'object Table qui appartient à l'espace de nom HTMLTable, il suffit de faire new HTMLTable\Table(). Les espaces de nom peuvent être imbriqués. Par exemple, nous pourrions avoir la classe Plugin\MassOCSImport\Server.
Une classe définie dans un espace de nom appel simplement les autres classes du même espace de nom. Donc, dans le namespace HTMLTable, la classe Row hérite simplement de ma classe Entity, elle même définie dans le namespace HTMLTable.
Pour faire appel à une classe à la racine, il suffit de préfixer son nom par '\'. Ainsi, la classe HTMLTable\Cell peut faire appel à \Session::addToNavigateListItems(...).

Il y a une chose à laquelle il faut faire très attention : PHP, comme le langage C, prend le caractère '\' comme caractère d'échappement. Par exemple '\n' correspond au retour à la ligne. Cela pose beaucoup de problèmes. En effet, lorsque l'on utilise une variable comme nom de classe dans un namespace, il faut, soit doubler les '\' dans les chaines de caratères encadré de double quotes, soit utiliser des simples quotes.

Problèmes avec les $_GET et $_POST

Le problème précédent est d'autant plus crucial avec les formulaires HTML : un champs contenant, par exemple, NetworkPort\Ethernet, renverra la valeur NetworkPort\\Ethernet dans les variales $_POST, $_GET et $_REQUEST. Il faut donc penser à utiliser, systématiquement stripslashes sur ce type de champs.

Interaction avec la base de données SQL

Noms des tables associés aux espaces de noms

Dans ses versions les plus récentes, MySQL autorise le symbole '\' dans le nom des tables à la condition que le nom soit "quoté" (ie : entouré par '`'). Grâce au lourd travail de "Coding Standard", c'est maintenant quasiment le cas sur l'ensemble du coeur.
Donc, la fonction getTableForItemType fonctionne sans problème sur les espaces de noms. Ainsi, la table associée à l'élément NetworkPort\Alias serait `glpi_networkport\aliases`.

Si on veut pousser le formalisme plus loin, nous pourrions remplacer le préfixe glpi_ des tables de GLPI par glpi\. Ainsi, nous pourrions considérer la table `glpi\networkport\aliases` comme la table associée à la classe Alias, du composant NetworkPort, de GLPI. Mais cette dernière évolution est une autre histoire ...

Problème des classes utilisées en tant que valeur dans les tables

De même que PHP et C, MySQL utilise le '\' comme caractère d'échappement. Donc, tous les champs de même nature que les champs `itemtype` poseront problème lorsque les 'items' sont des classes dans des espaces de nom.
L'une des solution est de modifier les méthodes CommDBTM::AddToDB et CommonDBTM::updateInDB pour faire un addslashes sur toutes les valeurs intégrées dans les requètes SQL. Mais les effets de bord risquent d'être redoutables. Entre autre, comment vont se comporter des champs comme `comment` qui ont des retours à la ligne ('\n') ?
Une autre solution est de faire en sorte, dans la classe où on utilise ce type de champs, de préparer la valeur avant de la soumettre à MySQL.

Organisation des fichiers

Nous avons vu que les espaces de noms permettaient d'isoler des composants "autonomes". Cette isolation pourrait faire l'objet d'une arborescence à part. Ainsi, à chaque espace de nom correspondrait un sous-répertoire du répertoire $GLPI_ROOT/inc. Il faudra limiter le nombre d'espaces de nom afin de ne pas multiplier les répertoires et alourdir la navigation. Mais il ne faut pas oublier, non plus, qu'un espace de nom correspond à un composant autonome dont l'interface est relativement figée. Ainsi, soit on travail sur le composant en question, soit on l'utilise. Mais nous devrions rarement avoir besoin d'ouvrir des fichiers dans le coeur et dans plusieurs composants en même temps. Donc, la navigation devrait être relativement restreinte.

Mise en oeuvre

Pour mettre en oeuvre cette solution hiérarchique, il suffira d'une petite mise à jours des functions glpi_autoload et isPluginItemType. En effet, dans la première, il suffit de remplacer '\' (en fait '\\' car '\' est un caractère d'échappement) par '/' dans le nom du fichier à charger pour atteindre la classe. Dans la seconde function (isPluginItemType), il faut autoriser, également, '\' comme caractère valide dans le nom d'une classe.

les plugins

Dans l'idée proposée par MoYo, les plugins étaient gérés par des namespaces. Un namespace global Plugin pourrait contenir tous les plugin. Chacun des plugins aurait son propre espace de nom dans l'espace de nom Plugin. Par, le plugin Mass OSC Import et IPAM auraient respectivement Plugin\MassOSCImport et Plugin\IPAM comme espace de nom. Afin de rester cohérent en termes de composants, le gestionnaire de plugin (actuellement la classe Plugin) serait renommé en Plugin/Manager.

les composants extérieurs

Malheureusement Zend et ezComponent n'utilisent pas les espaces de noms. Sinon, le filtre dans glpi_autoload serait grandement simplifié : pour chaque classe, on extrait son namespace (ie : mot juste avant le premier '\') et un simple switch permettrait de savoir s'il s'agit d'un composant Zend, ezComponent, ou bien, même, d'un plugin.

Remi: Zend 2 utilise désormais les namespaces. Il me semble intéressant de respecter le standard PSR0 ce qui pourra permettre d'utilise un autoloader standard (ex, celui de ZF2) https://github.com/php-fig/fig-standards/blob/master/accepted/fr/PSR-0.md

namespace.diff Magnifier - Patch à appliquer pour un premier essai sur les namespace associés à des répertoires (1005 Bytes) webmyster, 03/07/2012 11:05 AM