Chapitre 6. Standardiser la classe de Bootstrap avec Zend_Application

Table des matières

6.1. Introduction
6.2. Etape 1: Modifier la classe ZFExt_Bootstrap
6.3. Etape 2: Editer les fichiers Index et htaccess
6.4. Etape 3: Ajouter le fichier de configuration de l'application
6.5. Etape 4: Gérer la configuration des valeurs par défaut des Composants Standard
6.6. Etape 5: Réparer ZFExt_Bootstrap
6.7. Etape 6: Intégrer la Configuration de l'Application dans des Méthodes de Ressources
6.8. Etape 7: Optimiser le code d'auto-chargement
6.9. Permettre à Zend_Loader_Autoload de charger des Classes dans des Espaces de Noms
6.10. Conclusion

6.1. Introduction

Jusque récemment, créer et gérer le bootstrapping d'une application basée sur Zend Framework était une tâche à la charge du développeur et de son imagination. Cela encourageait l'utilisation de plusieurs pratiques distinctes, allant de l'utilisation de scripts procéduraux monolithiques à la mise en place de structures complexes, en passant par l'écriture de classes, sans compter que cela rendait difficile la conception d'un outil en ligne de commande. Avec l'introduction de Zend_Application, la mise en place du boostrap a maintenant une base commune, utilisable pour toute application par n'importe quel développeur, ce qui est un pas en avant vers la standardisation de ce besoin commun à toutes les applications. Si seulement ils avaient rendu cela évident en l'appelant Zend_Bootstrap...

Zend_Application a été conçue de manière à être modulaire, personnalisable, et configurable avec un minimum d'efforts. Pour que sachions un peu de quoi il retourne, puisque nous utiliserons (beaucoup) Zend_Application au cours de ce livre, nous allons revoir notre exemple Hello World précédent, et ré-architecturer la classe ZFExt_Bootstrap. Une chose que je ne changerai pas est l'emplacement de notre bootstrap, qui restera /library/ZFExt/Bootstrap.php. Il n'y a pas de raison particulière pour laquelle nous devrions le conserver ici, si ce n'est que l'espace de noms ZFExt formera la base de notre bibliothèque générique d'applications, où nous conserverons toutes les classes spécifiques au Zend Framework, pour éventuellement pouvoir les réutiliser à l'avenir dans d'autres applications.

6.2. Etape 1: Modifier la classe ZFExt_Bootstrap

Les modifications que nous devons apporter à notre classe de bootstrap commencent par quelque chose de simple :

Nous aurons besoin d'effectuer quelques modifications pour en arriver à ce que nous faisions avec la classe ZFExt_Bootstrap de départ, mais si vous n'aviez aucune modification à apporter, votre création d'une classe de boostrap pourrait s'arrêter là. Sans que nous n'ayons à ajouter la moindre portion de code supplémentaire, Zend_Application peut initialiser tout ce qui est nécessaire, en utilisant les valeurs utiles par défaut de chaque composant.

Ici, nous étendons Zend_Application_Bootstrap_Bootstrap, qui hérite elle-même de Zend_Application_Bootstrap_BootstrapAbstract, et fourni tout ce qui est nécessaire pour un bootstrap typique, comme le chargement de Ressources, le dispatching via le Front Controller, et quelques vérifications pour être sûr que nous avons précisé un mode d'opération (production ou développement, par exemple).

6.3. Etape 2: Editer les fichiers Index et htaccess

Comme précédemment, notre fichier index.php dans le répertoire /public est l'endroit où nous commençons par inclure et exécuter le bootstrapping. Nous devons ajouter un brin de complexité ici. Cela signifie notamment définir quelques constantes pour qu'elles contiennent des chemins de l'application, le chargement d'une configuration pour diriger le bootstrapping de notre environnement, et enfin, lancer le boostrapping lui-même.

Ici, nous voyons que index.php est toujours l'emplacement pour la configuration de points spécifiques à l'environnement. C'est dans index.php que nous créons un certain de nombre de constantes, que nous configurons notre include_path, and et que nous lançons le processus de bootstrapping. En interne, Zend_Application charge notre classe ZFExt_Bootstrap, que nous configurerons via un fichier de configuration d'application, placé dans /config/application.ini pour qu'il soit pris en compte. Même si notre classe est vide, elle étend toujours une classe abstraite contenant, elle, toutes les méthodes nécessaires.

Un point à noter est que ces constantes doivent être utilisées judicieusement. Les constantes sont des valeurs globales accessibles depuis n'importe quel point de l'application, et comme toute autre variable globale, leur utilisation doit être minimisée et effectuée avec soin, parce que la tentation de les utiliser partout est toujours présente. D'autres applications pourraient bien ne même pas créer ces constantes, donc tout code qui en dépend peut ne pas être réutilisable. Une bien meilleure solution, en dehors de index.php, est de continuer à utiliser dirname() et realpath() et/ou de passer ces variables via un objet Registre, ou comme paramètres du Front Controller, accessibles depuis les actions de vos Contrôleurs.

En m'écartant quelque peu du Guide de Référence, je maintiens le fichier index.php en me conformant aux normes de codage de Zend Framework. Il est préférable de ne pas utiliser de raccourcis ou d'écritures abbrégées, puisqu'ils ne sont pas vraiment faciles à lire.

Vous noterez que notre fichier index.php fait maintenant référence, par défaut, à une configuration de "production" en l'absence d'une variable d'environnement assigée à la constante APPLICATION_ENV. De toute évidence, nous ne voulons pas développer en utilisant une configuration de production, sauf si nous aimons débugger une application qui, mystérieusement, n'affiche pas ses erreurs, mais nous pouvons résoudre ce problème en ajoutant la définition de la variable d'environnement correspondante à notre fichier .htaccess :

SetEnv APPLICATION_ENV development

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d

RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ /index.php [NC,L]

Ceci fonctionne pour Apache. Pour d'autres serveurs web, il vous faudra consulter leur documentation.

6.4. Etape 3: Ajouter le fichier de configuration de l'application

Un des principaux avantages de l'utilisation de Zend_Application est que, une fois que vous avez supprimé le besoin de code personnalisé, vous pouvez concentrer vos efforts sur la mise en place des valeurs par défaut des composants, et gérer tout le reste via de la configuration. Comme le contenu de notre index.php semblait le suggérer plus haut, nous devrions ajouter un fichier de configuration dans /config/application.ini, qui contiendra :

[production]
phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0
bootstrap.path = APPLICATION_ROOT "/library/ZFExt/Bootstrap.php"
bootstrap.class = "ZFExt_Bootstrap"
resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"

[staging : production]

[testing : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1
resources.frontController.throwExceptions = 1

[development : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1
resources.frontController.throwExceptions = 1

Ici, le fichier de configuration est découpé en quatre modes distincts : production, staging, testing, et development. Tous ces modes héritent toutes les valeurs mises en place pour la production, mais peuvent définir des exceptions. Par exemple, la configuration de production désactive display_errors, alors que les modes de développement et de test assurent que cette directive sera activée. Vous pouvez faire confiance à Zend_Application, qui chargera le mode approprié en se basant sur la valeur que lui avons indiquée via la constante APPLICATION_ENV, que nous avons définie dans index.php.

Les valeurs d'INI utilisées peuvent paraître un peu étranges, puisqu'elles montrent des constantes PHP suivies d'un espace, puis d'un chemin relatif entre guillemets doubles à partir du chemin absolu défini par ces constantes. Zend_Application se chargera en interne de la concaténation de ces deux parties ; mais notez que vous pouvez configurer des chemins de cette manière pour le composant. En fait, vous pouvez aussi définir des listes à partir de fichiers de configuration .ini, comme nous le verrons dans de futurs chapîtres.

Zend_Application partage toute la configuration en quelques catégories, identifiables au sein du fichier de configuration par leurs préfixes. "phpSettings" fait référence à tout ce que vous pourriez définir en utilisant ini_set() en PHP. "includePaths" contient tous les chemins que vous pourriez vouloir ajouter à l'include_path de PHP (en dehors de ceux définis dans index.php). Par exemple, je pourrais utiliser :

includePaths.foolib = APPLICATION_ROOT "/foolib/lib"

A la place, je configures plus directement l'include_path depuis index.php pour les répertoires standard /library et /vendor, mais vous pourriez en avoir d'autres qui auraient aussi besoin d'être ajoutés. "bootstrap" indique à Zend_Application où notre classe de Bootstrap se trouve, et quel nom de classe est utilisé (rappelez-vous que nous avons toujours besoin de notre classe ZFExt_Bootstrap pour modifier la façon dont le bootsrapping configure certains composants).

Et enfin, nous avons "resource", qui fait référence à des Ressources de Zend_Application.

Pour faire simple, une Ressource Zend_Application est une classe que connait Zend_Application, qui pourra la configurer durant le boostrapping pour utilisation ultérieure. Au-dessus, nous avons défini des options pour un FrontController (les noms d'options ont leur première lettre en minuscule) pour configurer l'instance de Zend_Controller_Front que Zend_Application utilisera lorsque notre application sera en train de fonctionner. Pour l'instant, nous indiquons seulement à Zend_Controller_Front où est-ce que notre répertoire par défaut, contenant les classes de Contrôleurs, se trouve, et qu'il doit lever des exceptions pour les modes de développement et de test. Si la convention de configuration vous semble confuse, "controllerDirectory" correspond à Zend_Controller_Front::setControllerDirectory(), tout comme si nous utilisions une liste de valeurs de configuration, en utilisant la même convention pour faire correspondre des clefs de tableaux à méthodes setter auxquelles chaque clef correspond.

6.5. Etape 4: Gérer la configuration des valeurs par défaut des Composants Standard

Dans notre classe ZFExt_Bootstrap de départ, j'avais fait remarquer que certains composants sont configurés par défaut d'une manière qui n'est pas forcément adaptée à nos besoins. Par exemple, Zend_View utilise l'encodage ISO-8859-1 par défaut, ce qui est correct, pour peu que vous évitiez tout caractère accentué ou multi-octets. Vous pouvez configurer l'instance par défaut de Zend_View comme nous l'avions fait au départ, à peu de choses près de la même manière, maintenant que nous utilisons Zend_Application :

Nous voyons ici que notre classe de Bootstrap retouchée peut configurer une instance de Zend_View en appelant _initView(), qui est quelque chose à quoi nous faisons référence sous le terme de Méthode de Ressource, puisqu'elle configure ou modifie une Ressource pour que nous puissions l'utiliser. Ici, nous configurons une nouvelle instance de Zend_View pour qu'elle soit utilisée par l'aide d'action ViewRenderer (nous ferons connaissance des aides d'action plus tard), où elle agira en tant qu'instance de Zend_View par défaut pour le rendering des templates de l'application. Toutes les Méthodes de Ressources qui doivent être exécutées doivent respecter le format "_initResourceName()" s'il s'agit de méthodes protégées. Vous pouvez effectuer la même chose avec des méthodes publiques en les définissant sous la forme "bootstrapResourceName()". Le choix d'utiliser des méthodes publiques ou protégées vous revient.

Au sein de ces Méthodes de Ressources, nous pouvons en faire un peu plus, en utilisant le système de Ressources de Zend_Application. Pour faire simple, Zend_Application définit un certain nombre de classes appelées Plugins de Ressources, qu'il utilise pour initialiser les Ressources, comme alternative aux plus simples Méthodes de Ressources.

Donc, qu'est-ce qu'une Ressource après tout cela ? Le terme de Ressource peut porter à confusion, du fait qu'il ne raconte pas toute l'histoire à lui tout seul. La meilleure façon d'y penser est en termes de configuration d'objets uniques. Notre application n'a généralement besoin que d'une seule instance de chaque objet, au cours de son bootstrapping. Elle a besoin d'une instance de Zend_View, d'une instance de Zend_Controller_Front, d'une instance d'un Router, etc. Donc, une Resource est unique : une seule de chaque sorte. L'ensemble d'actions requises pour créer, configurer, et enregistrer ces ressources uniques avec Zend_Application (et la classe de bootstrap) vient sous deux formes alternatives distinctes : les Méthodes de Ressources, et les Plugins de Ressources. Ces deux solutions suivent une convention qui dit que la Ressource à laquelle elles s'appliquent est utilisée dans le nom de la méthode pour une Méthode de Ressource, et dans le nom de la classe pour un Plugin de Ressource. Donc, _initView() crée une Ressource nommée View. Mais, attendez : il y a aussi un Plugin de Ressource (Zend_Application_Resource_View) qui peut aussi créer une Ressource nommée View. Pouvons-nous avoir deux Ressources View ? La réponse est non : nous ne pouvons en avoir qu'une seule. En définissant une Méthode de Ressource, nous écrasons tout Plugin de Ressource applicable à la même Ressource.

Un Plugin de Ressource est une classe qui étend Zend_Application_Resource_ResourceAbstract (ou Zend_Application_Resource_Resource) qui s'occupe de l'initialisation, de la configuration, et du passage de ces classes en tant qu'objets au Front Controller. Une Méthode de Ressource est comme un Plugin de Ressource, mais elle est définie dans le bootstrap, plutôt que d'être placée dans sa propre classe distincte. Pour créer de nouveaux objets à utiliser pendant le boostrapping, vous pouvez donc ajouter une classe personnalisée de Plugin de Ressource, ou une Méthode de Ressource comme alternative plus courte.

Bien entendu, Zend_Application va automatiquement gérer, sans interférence, quelques classes standard dont votre application pourrait avoir besoin. Les Plugins de Ressources fournis avec Zend_Application comprennent :

Zend_Application_Resource_Db
Zend_Application_Resource_FrontController
Zend_Application_Resource_Router
Zend_Application_Resource_Modules
Zend_Application_Resource_Navigation
Zend_Application_Resource_Session
Zend_Application_Resource_View
Zend_Application_Resource_Layout
Zend_Application_Resource_Locale
Zend_Application_Resource_Translate
[Note]Note

Au moment de la sortie de Zend Framework 1.9.0, plusieurs de ces classes ne sont pas citées dans le Guide de Référence. Seules celles absolument nécessaires mènent à des ressources initialisées, ce qui signifie que Zend_Application_Resource_Db ne fonctionnera pas immédiatement, et se plaindra d'options de configuration manquantes, parce qu'elle n'est pas lancée par défaut, à moins que ne la configuriez.

Dans notre méthode _initView(), nous avons créé un objet Zend_View de remplacement ou de substitution, parce que Zend_Application_Resource_View va juste créer une instance par défaut avec l'encodage de caractères ISO-8859-1 et quelques autres options par défaut. En retournant la nouvelle instance de Zend_View depuis _initView(), Zend_Application va prendre en compte le remplacement, et ne tentera pas d'écraser nos modifications en lançant Zend_Application_Resource_View pour obtenir une instance par défaut de Zend_View, comportant les problèmes que nous venons de corriger.

Lorsque nous créons une nouvelle Ressource pour en remplacer une autre, nous n'avons pas à récupérer celle initialement mise en place dans Zend_Application par le Plugin de Ressource par défaut, à moins que cela ne soit nécessaire. Ajoutons maintenant une autre méthode de ressource, _initFrontController(), qui modifie seulement quelques options d'une ressource existante, telle que mise en place par Zend_Application_Resource_Frontcontroller.

Dans notre classe de bootstrap de départ, nous voulions nous assurer que, par défaut, toutes les réponses utiliseraient une en-tête Content-Type valant "text/html; charset=UTF-8". Ici, nous faisons la même chose en utilisant la méthode getResource() pour obtenir une instance de Zend_Controller_Front créée et configurée par Zend_Application_Resource_Frontcontroller et uniquement faire en sorte qu'elle utilise notre propre objet de Réponse plutôt que d'en créer un par défaut lorsque nécessaire. Avant de récupérer la Ressource FrontController, c'est-à-dire un objet de type Zend_Controller_Front, nous devons tout d'abord nous assurer que Zend_Application fasse tout ce qui est nécessaire pour la créer.

Ceci est fait en passant le nom de la Ressource (c'est-à-dire, le terme final dans le nom du Plugin de Ressource correspondant) à la méthode bootstrap(). Cela force Zend_Application à bootstrapper uniquement cette Ressource. Cette méthode bootstrap() est relativement souple, et accepte une liste de Noms de Ressources si vous avez besoin que plusieurs d'entre elles soient disponibles immédiatement, sans attendre que l'exécution globale du bootstrap n'ait été effectuée.

Vous pouvez aller plus loin en remplaçant simplement les Plugins de Ressources par défaut. Je ne traiterai pas ce point ici, puisque nous verrons comment ajouter des Plugins de Ressources personnalisés pour d'autres objets utilisés par notre application plus loin dans ce livre.

Maintenant, comparons la classe ZFExt_Bootstrap de départ avec sa version revue. Moins de code, gérée par configuration, facile à utiliser, et extensible via des Plugins de Ressources. La nouvelle version est de toute évidence une amélioration. Bien entendu, comprendre comment cela fonctionne est encore une autre marche sur la route qui vous ménera au statut de Guru Zend Framework, mais c'est un coût que l'on retrouve toujours lorsque l'on utilise plus de classes abstraites, qui n'en sont pas pour autant moins extensibles et réutilisables que leurs alternatives monolithiques.

6.6. Etape 5: Réparer ZFExt_Bootstrap

Si vous essayez d'accéder à http://helloworld.tld une nouvelle fois, vous remarquerez quelque chose de bizarre. Une exception quelque peu anonyme est maintenant levée, indiquant "Circular resource dependency detected". Cela arrive parce que nous avons défini une Méthode de Ressource _initFrontController(), qui entre en conflit avec Zend_Application_Resource_Frontcontroller lorsque nous appelons bootstrap('FrontController'). En pratique, nous violons la règle qui définit qu'une Ressource doit être unique : lorsque nous essayons d'utiliser la Méthode de Ressource et forçons l'utilisation du Plugin de Ressource (qui est lancée par bootstrap()), Zend_Application interprête cela comme une tentative de créer deux objets similaires, alors que nous n'avons besoin que d'un. Jusqu'à ce que nous ayons l'habitude de penser au travail effectué par le bootstrap comme des Ressources uniques, c'est une erreur qui reviendra souvent.

Ce point est uniquement pour mettre en évidence l'importance des Méthodes Ressources par rapport aux Plugins de Ressources (ainsi que pour expliquer ce qui cause ce petit problème un peu obscur lorsque l'on commence à travailler avec Zend_Application). Vous pouvez utiliser l'une ou l'autre des deux solutions, mais jamais les deux avec le même Nom de Ressource en même temps. Plus haut, notre méthode _initView() fonctionnait parce que nous n'utilisons aucune référence à Zend_Application_Resource_View : notre Méthode de Ressource la remplace. Si nous avions essayé de modifier l'objet généré par Zend_Application_Resource_View en utilisant les méthodes bootstrap() et getResource() pour générer et obtenir l'objet, nous aurions eu à renommer la Méthode de Ressource, pour mettre en évidence le fait que nous étions en train de construire par-dessus la Ressource initialisée par le Plugin, en en créant une version modifiée (en pratique, une Ressource différente, même si la différence n'est qu'un point de configuration).

Ceci illustre un point important : même si Zend_Application parle de Ressources, vous pouvez avoir un objet unique représenté par deux ou plus Ressources nommées. Cela semble un peu idiot, puisque, finalement, seul cet objet est utilisé, indépendamment du nombre de Noms de Ressources qui y font référence. Cela dit, c'est uniquement un artifice : pour pouvoir modifier des objets après leur mise en place initiale par les Plugins ou Méthodes (non recommandé : l'ordre des méthodes est un peu traitre), nous devons utiliser un Nom différent de Ressource. Il n'est pas nécessaire que vous compreniez pourquoi ; c'est juste comme ça que ça fonctionne.

Dans _initFrontController(), nous avons fait l'erreur de croire que nous pouvions modifier un Front Controller existant en le chargeant depuis Zend_Application_Resource_FrontController, sans réaliser que nous effectuions ceci dans une Méthode de Ressource en utilisant le même nom de Ressource. A partir de l'instant où une unité de Ressource essaye d'utiliser une autre unité de Ressource nommée à l'identique, la confusion est de la partie, puisque nous ne pouvons pas avoir deux objets qui représentent la même Ressource ; donc, Zend_Application lève une Exception en se plaignant à propos du noeud de dépendances que nous essayons de créer. C'est un filet de sécurité délibérément mis en place.

Pour résoudre ce conflit, nous devrions renommer toute Méthode de Ressource non destinée à remplacer un Plugin de Ressource, en utilisant des noms un peu plus uniques. Dans ce cas, j'ai décidé de préfixer le Nom de Ressource existant "FrontController" par "Modified", de manière à indiquer que notre Méthode de Ressource n'écrase pas un Plugin de Ressource, ce qui signifie que nous pouvons utiliser le résultat de ce Plugin de Ressource quand il est lancé plutôt que d'effectuer notre propre travail séparé de création. Nous ne retournons pas non plus l'objet, puisque le Plugin de Ressource l'enregistrera pour utilisation de son côté.

Maintenant, nous pouvons essayer http://helloworld.tld une fois de plus, sans rencontrer erreur ni exception.

6.7. Etape 6: Intégrer la Configuration de l'Application dans des Méthodes de Ressources

Dans le fichier de configuration de notre application, application.ini, nous avons noté que nous pouvions définir la configuration des Ressources en utilisant le préfixe "resources". Ces entrées de configuration sont automatiquement utilisées par les Plugins de Ressources de Zend_Application pour passer les options aux objets qu'ils créent. Donc, pour notre Ressource FrontController, nous pouvons ajouter des entrées de ce type :

resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"

Ici, le nom de la Ressource est camel-cased, avec la première lettre en minuscule ; autrement dit, FrontController devient frontController. Ce n'est pas quelque chose dont nous avons besoin de nous soucier immédiatement, mais nous pouvons nettoyer un petit peu notre Méthode de Ressource remplaçant Zend_View en faisant en sorte que toutes les options de configuration ajoutées à application.ini soient passées à la nouvelle instance. Même si nous n'y gagnons rien d'autre, cela nous permet de définir l'encodage de caractères dans le fichier de configuration.

Maintenant, nous pouvons placer la configuration de l'encodage de caractères, ou toute autre option de configuration personnalisée dont nous aurions besoin, dans le fichier de configuration application.ini.

[production]
phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0
bootstrap.path = APPLICATION_ROOT "/library/ZFExt/Bootstrap.php"
bootstrap.class = "ZFExt_Bootstrap"
resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
resources.view.encoding = "UTF-8"
resources.view.doctype = "XHTML1_STRICT"
resources.view.contentType = "text/html;charset=utf-8"
resources.modifiedFrontController.contentType = "text/html;charset=utf-8"

[staging : production]

[testing : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1
resources.frontController.throwExceptions = 1

[development : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1
resources.frontController.throwExceptions = 1

6.8. Etape 7: Optimiser le code d'auto-chargement

Dans notre classe de bootstrap précédente, nous avions créé une méthode d'autoload personnalisée, qui n'effectuait aucune vérification sur les fichiers, et essayait juste d'exécuter un include() en supposant que toutes les classes correspondaient à leurs fichiers en utilisant la convention PEAR. Ce choix avait été effectué pour éviter de faire appel à la méthode Zend_Loader::loadClass() de l'autoloader plus typique utilisé dans les applications Zend Framework, qui fait tout un tas de vérifications d'erreurs, généralement inutiles. Zend_Application est aussi conçu de manière à implémenter un mécanisme d'autoload en utilisant un autre nouveau composant, Zend_Loader_Autoloader. Malheureusement, Zend_Loader_Autoloader (qui ajoute des fonctionnalités nettement améliorées d'auto-chargement de classes) utilise la même méthode Zend_Loader::loadClass(), que nous souhaitions éviter.

Nous pouvons toujours implémenter notre méthode plus légère, mais plus depuis la classe de bootstrap. A la place, il nous faut réinitialiser la méthode d'auto-chargement par défaut de Zend_Loader_Autoloader avant que Zend_Application ne soit initialisée, et cela ne peut être fait que depuis index.php.

Puisque nous ne pouvons même pas faire référence au bootstrap avant que Zend_Application n'ait été initialisée, nous pouvons plutôt passer une fonction anonyme, créée à la volée, à setDefaultAutoloader().

6.9. Permettre à Zend_Loader_Autoload de charger des Classes dans des Espaces de Noms

En PHP, où les bibliothèques respectent la convention PEAR, tous les noms de classes comportent un préfixe commun, auquel nous faisons référence sous le terme de "namespace" (ce qui n'est pas un espace de nom réel de la manière dont PHP 5.3 les défini). Notre autoloader est configuré de manière à reconnaitre dans les noms de classes les espaces de noms incluant "Zend_" et "ZendX_". Pour pouvoir charger d'autres classes namespacées, nous devons en premier lieu indiquer à l'autoloader qu'elles existent. Cela dit, nous pouvons commencer par nous demander pourquoi est-ce que cela est nécessaire.

Le problème avec la méthode d'auto-chargement de départ était simple : elle sait charger à peu près n'importe quoi. Au premier coup d'oeil, ça a l'air fantastique, c'est simple, facile à comprendre, et ne nécessite aucune configuration. Donc, où est le problème ? Le problème avec l'idée de charger n'importe quoi est qu'elle n'offre aucun contrôle. Parfois, vous voudriez vous assurer que seules certaines bibliothèques soient chargées. En plus de cela, la restriction mise en place permet aussi des recherches plus rapides.

La nouvelle fonctionnalité d'espaces de noms n'est pas parfaite, mais c'est principalement dû au fait que certaines bibliothèques n'ont pas un préfixe de plus haut niveau. Par exemple, les composants PEAR ne commencent pas par PEAR_, ce qui signifie que vous pouvez avoir HTTP_Client, Crypt_RSA, et ainsi de suite, qui ne partagent pas un préfixe commun. Un problème similaire existe avec n'importe quelle classe "racine" ; par exemple; HTMLPurifier utilise le préfixe d'espace de nom HTMLPurifer_, sauf pour une classe racine dans HTMLPurifier.php. Dans ces circonstances, vous pourrez avoir besoin de revenir au comportement de départ, où les espaces de noms ne sont pas suivis ni restreint, en utilisant :

En d'autres circonstances, une bibliothèque peut utiliser son propre autoloader, que vous pouvez enregistrer en tant qu'alternative à celui implémenté par défaut par Zend_Loader_Autoloader.

Notez que cela, puisque HTMLPurifier n'utilise pas d'espace de nom, ajoute un nouvel autoloader global, un peu comme l'option de fallback fait fonctionner l'autoloader par défaut à peu de chose près sans aucune restriction. Vous pouvez passer un autoloader restreint à un espace de noms de manière similaire, pour qu'il ne soit appelé que lorsqu'une classe avec un espace de nom spécifique est détectée.

Cela dit, assumons pour l'instant que cette solution par défaut et les autres autoloaders ne soient pas nécessaire. Le contre-coup du nouvel autoloader est qu'il nous faut enregistrer tous les espaces de noms que nous avons l'intention d'utiliser. Bien que nous puissions effectuer ceci sous forme de code dans index.php, il est plus simple d'en garder une trace dans notre fichier application.ini, ce qui rend plus facile l'ajout d'espaces de noms lorsqu'ils sont nécessaires. Voici un exemple où nous avons l'intention d'utiliser une bibliothèque (en fait, la bibliothèque de notre future application) dont toutes les classes sont préfixées par "ZFExt_". Comme vous pouvez probablement le voir, vous pouvez continuer à ajouter des espaces de noms de cette manière, puisque les crochets [] indiquent qu'ils seront ajoutés à une liste au moment où le fichier .ini sera analysé par Zend_Config (qui gère toutes les analyses et chargements de fichiers de configuration au sein du Framework) :

[production]
phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0
bootstrap.path = APPLICATION_ROOT "/library/ZFExt/Bootstrap.php"
bootstrap.class = "ZFExt_Bootstrap"
resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
resources.view.encoding = "UTF-8"
resources.view.doctype = "XHTML1_STRICT"
resources.view.contentType = "text/html;charset=utf-8"
resources.modifiedFrontController.contentType = "text/html;charset=utf-8"
autoloaderNamespaces[] = "ZFExt_"

[staging : production]

[testing : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1
resources.frontController.throwExceptions = 1

[development : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1
resources.frontController.throwExceptions = 1

6.10. Conclusion

C'état une rapide introduction (enfin, vous pouvez toujours apprendre à lire rapidement) à Zend_Application. En tant que personne qui a développée sa propre solution de son côté, je suis extrêmement content de pouvoir l'adopter à la place. Cela me permet d'être sûr que d'autres développeurs pourront suivre mon processsus de bootstrapping dans avoir à apprendre une nouvelle approche (Parmi les centaines qui existent probablement déjà). C'est la force d'enfin avoir une approche standard au bootstrapping d'applications.

Vous verrez plus de points en rapport avec Zend_Application au fur et à mesure que le livre avancera, puisqu'il y a plein d'objets et d'autres portions de comportements que nous pourrons avoir à modifier dans nos applications, et qu'utiliser le bootstrap pour effectuer ces initialisations est la meilleure approche possible. Pour finir, notez que Zend_Tool, qui n'est pas encore couvert par ce livre, utilise Zend_Application pour gérer les applications.