1 <?xml version="1.0" encoding="UTF-8"?>
2 <!-- EN-Revision: 20876 -->
4 <sect1 id="performance.classloading">
5 <title>Chargement des classes</title>
8 Tous ceux qui ont déjà réalisé le profilage d'une application Zend Framework
9 reconnaîtront immédiatement que le chargement des classes y est relativement coûteux. Entre
10 le nombre important de fichier de classe qui doivent être chargées pour un grand nombre de
11 composants et l'utilisation des plugins qui n'impliquent pas une relation 1:1 entre leur nom
12 de classe et le système de fichier, les différents appels de <code>include_once</code> et
13 <code>require_once</code> peuvent être problématique. Ce chapitre a pour but de fournir des
14 solutions concrètes pour solutionner ces problèmes.
17 <sect2 id="performance.classloading.includepath">
18 <title>Comment optimiser mon include_path ?</title>
21 Une optimisation triviale pour accélérer la vitesse de chargement des classes est
22 de faire attention à votre <code>include_path</code>. En particulier, vous devriez faire
23 quatre choses : utilisez des chemins absolus (ou des chemins relatifs à des chemins
24 absolus), réduire le nombre des chemins à inclure, définir le dossier de Zend Framework
25 le plus tôt possible dans l'<code>include_path</code> et inclure le dossier courant en
26 dernier dans votre <code>include_path</code>.
29 <sect3 id="performance.classloading.includepath.abspath">
30 <title>Utiliser des chemins absolus</title>
33 Tandis que ceci peut sembler une micro-optimisation, le fait est que si vous
34 ne le faites pas, vous n'obtiendrez qu'un très petit avantage de la mise en cache du
35 realpath de PHP, et en conséquence, le cache d'opcode ne fonctionnera pas tout à
36 fait comme vous pourriez l'imaginer.
40 Il y a deux manières simples de s'assurer de ceci. Premièrement, vous pouvez
41 le mettre en dur dans votre <filename>php.ini</filename>,
42 <filename>httpd.conf</filename>, ou <filename>.htaccess</filename>. Deuxièmement,
43 vous pouvez utiliser la fonction <code>realpath()</code> de PHP au moment du
44 paramétrage de votre <code>include_path</code> :
47 <programlisting language="php"><![CDATA[
49 realpath(dirname(__FILE__) . '/../library'),
52 set_include_path(implode(PATH_SEPARATOR, $paths);
56 Vous <emphasis>pouvez</emphasis> utiliser des chemins relatifs - du moment
57 qu'ils sont relatifs à un chemin absolu :
60 <programlisting language="php"><![CDATA[
61 define('APPLICATION_PATH', realpath(dirname(__FILE__)));
63 APPLICATION_PATH . '/../library'),
66 set_include_path(implode(PATH_SEPARATOR, $paths);
70 Néanmoins, c'est typiquement une tâche insignifiante de fournir simplement le
71 chemin à <code>realpath()</code>.
75 <sect3 id="performance.classloading.includepath.reduce">
76 <title>Réduire le nombre de dossier défini dans l'include_path</title>
79 Les chemins d'inclusion sont scannés dans l'ordre dans lequel ils apparaissent
80 dans l'<code>include_path</code>. Évidemment, ceci veut dire que vous aurez un
81 résultat plus rapide si le fichier est trouvé dans le premier chemin scanné que si
82 vous le trouvez dans le dernier chemin scanné. De plus, une amélioration plutôt
83 évidente est de diminuer tout simplement le nombre de chemins dans votre
84 <code>include_path</code> à seulement de ce que vous avez réellement besoin.
85 Regardez chaque chemin que vous avez défini dans votre include_path pour déterminer
86 si vous avez réellement besoin d'une fonctionnalité dans votre application ; si
87 ce n'est pas le cas, enlevez le.
91 Une autre optimisation consiste en la combinaison de chemins. Par exemple,
92 Zend Framework suit la convention de nommage PEAR ; ainsi , si vous utilisez
93 des librairies PEAR (ou d'autres framework ou librairies de composants qui
94 respectent la convention de nommage PEAR), essayez de mettre toutes ces librairies
95 dans le même chemin de l'<code>include_path</code>. Ceci peut souvent être réalisé
96 par quelque chose d'assez simple comme de créer des liens symboliques vers une ou
97 plusieurs bibliothèques dans un dossier commun.
101 <sect3 id="performance.classloading.includepath.early">
103 Définir le dossier de Zend Framework le plus tôt possible dans l'include_path
107 Pour continuer avec les suggestions précédentes, une autre optimisation
108 évidente est de définir le dossier de Zend Framework le plus tôt possible dans votre
109 <code>include_path</code>. Dans la plupart des cas, il devrait être le premier de la
110 liste. Ceci permet de s'assurer les fichiers de Zend Framework à inclure le sont dès
115 <sect3 id="performance.classloading.includepath.currentdir">
116 <title>Définir le dossier courant le plus tard possible ou pas du tout</title>
119 La plupart des exemples d'<code>include_path</code> montre l'utilisation du
120 répertoire courant ("<code>.</code>"). Ceci est pratique pour s'assurer que les
121 scripts dans le même dossier que le fichier courant peuvent aussi être chargés.
122 Cependant ces mêmes exemples montrent souvent ce dossier comme étant le premier de
123 la liste des include_path - ce qui veut dire l'arbre de dossiers courant est
124 toujours scanné en premier. La plupart du temps, avec Zend Framework, ce n'est pas
125 nécessaire, et ce dossier peut tout naturellement être mis en dernière position de
129 <example id="performance.classloading.includepath.example">
130 <title>Exemple : optimisation de l'include_path</title>
133 Essayons de mettre ensemble toutes ces suggestions. Considérons que nous
134 utilisons une ou plusieurs composants PEAR en conjonction avec Zend Framework -
135 par exemple les composants PHPUnit et Archive_Tar - et qu'il est
136 occasionnellement nécessaire d'inclure les fichiers relativement au fichier
141 Premièrement, nous allons créer un dossier pour les librairies dans notre
142 projet. Dans ce même dossier, nous allons créer un lien symbolique vers notre
143 dossier Zend Framework "<filename>library/Zend</filename>", ainsi que les
144 dossiers nécessaires dans notre installation PEAR :
147 <programlisting language="php"><![CDATA[
156 Ceci nous permet d'ajouter notre propre librairie si nécessaire, tout en
157 laissant intact les librairies partagées.
161 Ensuite, nous optons pur la création de notre <code>include_path</code>
162 par programme à l'intérieur de notre fichier
163 <filename>public/index.php</filename>. Ceci nous permet de déplacer notre code
164 dans le système de fichiers, sans devoir éditer l'<code>include_path</code> à
169 Nous emprunterons des idées à chacune des suggestions ci-dessus : nous
170 utiliserons les chemins absolus, déterminé en utilisant le
171 <code>realpath()</code> ; nous positionnerons Zend Framework au plus tôt
172 dans l'<code>include_path</code> ; nous avons déjà vérifié les chemins
173 d'inclusions nécessaires ; et nous mettrons le dossier courant comme
174 dernier chemin. En fait, nous faisons tout bien ici - nous allons donc terminer
175 avec seulement deux chemins.
178 <programlisting language="php"><![CDATA[
180 realpath(dirname(__FILE__) . '/../library'),
183 set_include_path(implode(PATH_SEPARATOR, $paths));
189 <sect2 id="performance.classloading.striprequires">
190 <title>Comment éliminer les déclarations require_once non nécessaires ?</title>
193 Le chargement tardif ("lazy loading") est une technique d'optimisation conçue pour
194 repousser l'opération coûteuse de chargement d'une classe jusqu'au dernier moment
195 possible - c'est-à-dire lors de l'instanciation d'un objet de cette classe, ou lors de
196 l'utilisation d'une constante de classe ou d'une propriété statique. PHP supporte tout
197 ceci via l'autoloading (ou "chargement automatique"), ce qui vous permet de définir un
198 ou plusieurs callbacks à exécuter dans le but de faire correspondre un nom de classe à
203 Cependant, la plupart des avantages que vous pourrez retirer de l'autoloading sont
204 diminués si le code de votre librairie exécute toujours des appels à
205 <code>require_once</code> - ce qui est précisément le cas de Zend Framework. La question
206 est donc : comment éliminer ces déclarations <code>require_once</code> dans le but de
207 maximiser les performances de l'autoloader.
210 <sect3 id="performance.classloading.striprequires.sed">
211 <title>Effacer les appels de require_once avec find et sed</title>
214 Une manière simple d'effacer les appels require_once est d'utiliser les
215 utilitaires Unix "find" en conjonction avec "sed" pour passe en commentaires tous
216 les appels. Essayez d'exécuter les commandes suivantes (où "%" indique le prompteur
220 <programlisting language="shell"><![CDATA[
221 % cd chemin/vers/la/librarie/ZendFramework
222 % find . -name '*.php' -not -wholename '*/Loader/Autoloader.php' \
223 -not -wholename '*/Application.php' -print0 | \
224 xargs -0 sed --regexp-extended --in-place 's/(require_once)/\/\/ \1/g'
228 Cette ligne unique (coupée en deux pour la lisibilité) itère parmi les
229 fichiers PHP et y remplace toute les instances de <code>require_once</code> par
230 <code>//require_once</code>, c'est-à-dire en commentant toutes ces lignes (tout
231 en maintenant les appels à <function>require_once</function> dans
232 <classname>Zend_Application</classname> et
233 <classname>Zend_Loader_Autoloader</classname>, puisque ces classes tomberont en
234 erreur sans ceux-ci).
238 Cette commande peut être simplement ajoutée à un script de construction
239 automatique ou à un processus de mise en production, permettent ainsi d'augmenter
240 les performances de votre application en production. Il est à noter, cependant, que
241 si vous utilisez cette technique, vous <emphasis>devez</emphasis> utiliser
242 l'autoloading ; vous pouvez l'activer dans votre fichier
243 <filename>public/index.php</filename> en ajoutant le code suivant :
246 <programlisting language="php"><![CDATA[
247 require_once 'Zend/Loader/Autoloader.php';
248 Zend_Loader_Autoloader::getInstance();
253 <sect2 id="performance.classloading.pluginloader">
254 <title>Comment accélérer le chargement des plugins ?</title>
257 Certains composants utilisent les plugins, ce qui vous permet de créer vos propres
258 classes afin de les utiliser avec le composant, de même que de surcharger les plugins
259 standard existants embarqués dans Zend Framework. Ceci fournit une importante
260 flexibilité au framework, mais a un prix : le chargement des plugins est une tâche
265 Le chargeur de plugins vous permet de définir des paires préfixe de classe /
266 chemin, vous autorisant ainsi à spécifier des fichiers de classe dans des chemins de
267 dossiers non standard. Chaque préfixe peut avoir de multiples chemins associés. En
268 interne, le chargeur de plugins boucle à travers chaque préfixe, et ensuite à travers
269 chaque chemin lui étant associé, en testant l'existence du fichier et s'il est
270 accessible dans ce chemin. Il le charge ensuite, et teste pour voir si la classe
271 recherchée est bien disponible. Comme vous pouvez l'imaginer, tout ceci entraîne des
272 appels aux stats du système de fichiers.
276 Multipliez ceci par le nombre de composants qui utilisent le PluginLoader, et vous
277 aurez une idée de l'importance de ce problème. Au moment de l'écriture de ce document,
278 les composants suivants utilisent le PluginLoader :
284 <classname>Zend_Controller_Action_HelperBroker</classname> : aides
291 <classname>Zend_Dojo</classname> : aides de vues, éléments de formulaires
297 <para><classname>Zend_File_Transfer</classname> : adaptateurs</para>
302 <classname>Zend_Filter_Inflector</classname> : filtres (utilisé par l'aide
303 d'action <code>ViewRenderer</code> et <classname>Zend_Layout</classname>)
308 <para><classname>Zend_Filter_Input</classname> : filtres et validateurs</para>
313 <classname>Zend_Form</classname> : éléments, validateurs, filtres,
314 décorateurs, captcha et adaptateur pour les transferts de fichiers
319 <para><classname>Zend_Paginator</classname> : adaptateurs</para>
323 <para><classname>Zend_View</classname> : aides de vues, filtres</para>
327 <para>Comment réduire le nombre des appels réalisés ?</para>
329 <sect3 id="performance.classloading.pluginloader.includefilecache">
330 <title>Utiliser le fichier de cache des inclusions du PluginLoader</title>
333 Zend Framework 1.7.0 ajoute un fichier de cache des inclusions au
334 PluginLoader. Cette fonctionnalité écrit dans un fichier les appels
335 "<code>include_once</code>", que vous pouvez ensuite inclure dans votre fichier
336 d'amorçage. Même si ceci introduit de nouveaux appels include_once dans votre code,
337 cela permet de s'assurer que le PluginLoader les retournera au plus vite.
341 La documentation du PluginLoader <link
342 linkend="zend.loader.pluginloader.performance.example">inclue un exemple complet de
343 son utilisation</link>.