| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- <!-- EN-Revision: 13910 -->
- <sect1 id="performance.classloading">
- <title>Chargement des classes</title>
- <para>Tous ceux qui ont déjà réalisé le profilage d'une application Zend Framework reconnaîtront immédiatement que
- le chargement des classes y est relativement coûteux. Entre le nombre important de fichier de classe qui doivent
- être chargées pour un grand nombre de composants et l'utilisation des plugins qui n'impliquent pas une relation 1:1
- entre leur nom de classe et le système de fichier, les différents appels de <code>include_once</code> et
- <code>require_once</code> peuvent être problématique. Ce chapitre a pour but de fournir des solutions concrètes pour
- solutionner ces problèmes.</para>
- <sect2 id="performance.classloading.includepath">
- <title>Comment optimiser mon include_path?</title>
- <para>Une optimisation triviale pour accélérer la vitesse de chargement des classes est de faire attention à
- votre <code>include_path</code>. En particulier, vous devriez faire quatre choses : utilisez des chemins absolus
- (ou des chemins relatifs à des chemins absolus), réduire le nombre des chemins à inclure, définir le dossier de
- Zend Framework le plus tôt possible dans l'<code>include_path</code> et inclure le dossier courant en dernier
- dans votre <code>include_path</code>.</para>
- <sect3 id="performance.classloading.includepath.abspath">
- <title>Utiliser des chemins absolus</title>
- <para>Tandis que ceci peut sembler une micro-optimisation, le fait est que si vous ne le faites pas, vous
- n'obtiendrez qu'un très petit avantage de la mise en cache du realpath de PHP, et en conséquence, le cache
- d'opcode ne fonctionnera pas tout à fait comme vous pourriez l'imaginer.</para>
- <para>Il y a deux manières simples de s'assurer de ceci. Premièrement, vous pouvez le mettre en dur dans
- votre <filename>php.ini</filename>, <filename>httpd.conf</filename>, ou <filename>.htaccess</filename>.
- Deuxièmement, vous pouvez utiliser la fonction <code>realpath()</code> de PHP au moment du paramétrage de
- votre <code>include_path</code> :</para>
- <programlisting role="php"><![CDATA[
- $paths = array(
- realpath(dirname(__FILE__) . '/../library'),
- '.',
- );
- set_include_path(implode(PATH_SEPARATOR, $paths);
- ]]></programlisting>
- <para>Vous <emphasis>pouvez</emphasis> utiliser des chemins relatifs - du moment qu'ils sont relatifs à un
- chemin absolu :</para>
- <programlisting role="php"><![CDATA[
- define('APPLICATION_PATH', realpath(dirname(__FILE__)));
- $paths = array(
- APPLICATION_PATH . '/../library'),
- '.',
- );
- set_include_path(implode(PATH_SEPARATOR, $paths);
- ]]></programlisting>
- <para>Néanmoins, c'est typiquement une tâche insignifiante de fournir simplement le chemin à
- <code>realpath()</code>.</para>
- </sect3>
- <sect3 id="performance.classloading.includepath.reduce">
- <title>Réduire le nombre de dossier défini dans l'include_path</title>
- <para>Les chemins d'inclusion sont scannés dans l'ordre dans lequel ils apparaissent dans
- l'<code>include_path</code>. Évidemment, ceci veut dire que vous aurez un résultat plus rapide si le fichier
- est trouvé dans le premier chemin scanné que si vous le trouvez dans le dernier chemin scanné. De plus, une
- amélioration plutôt évidente est de diminuer tout simplement le nombre de chemins dans votre
- <code>include_path</code> à seulement de ce que vous avez réellement besoin. Regardez chaque chemin que vous
- avez défini dans votre include_path pour déterminer si vous avez réellement besoin d'une fonctionnalité dans
- votre application ; si ce n'est pas le cas, enlevez le.</para>
- <para>Une autre optimisation consiste en la combinaison de chemins. Par exemple, Zend Framework suit la
- convention de nommage PEAR ; ainsi , si vous utilisez des librairies PEAR (ou d'autres framework ou
- librairies de composants qui respectent la convention de nommage PEAR), essayez de mettre toutes ces
- librairies dans le même chemin de l'<code>include_path</code>. Ceci peut souvent être réalisé par quelque
- chose d'assez simple comme de créer des liens symboliques vers une ou plusieurs bibliothèques dans un
- dossier commun.</para>
- </sect3>
- <sect3 id="performance.classloading.includepath.early">
- <title>Définir le dossier de Zend Framework le plus tôt possible dans l'include_path</title>
- <para>Pour continuer avec les suggestions précédentes, une autre optimisation évidente est de définir le
- dossier de Zend Framework le plus tôt possible dans votre <code>include_path</code>. Dans la plupart des
- cas, il devrait être le premier de la liste. Ceci permet de s'assurer les fichiers de Zend Framework à
- inclure le sont dès le premier scan.</para>
- </sect3>
- <sect3 id="performance.classloading.includepath.currentdir">
- <title>Définir le dossier courant le plus tard possible ou pas du tout</title>
- <para>La plupart des exemples d'<code>include_path</code> montre l'utilisation du répertoire courant
- ("<code>.</code>"). Ceci est pratique pour s'assurer que les scripts dans le même dossier que le fichier
- courant peuvent aussi être chargés. Cependant ces mêmes exemples montrent souvent ce dossier comme étant le
- premier de la liste des include_path - ce qui veut dire l'arbre de dossiers courant est toujours scanné en
- premier. La plupart du temps, avec Zend Framework, ce n'est pas nécessaire, et ce dossier peut tout
- naturellement être mis en dernière position de la liste.</para>
- <example id="performance.classloading.includepath.example">
- <title>Exemple : optimisation de l'include_path</title>
- <para>Essayons de mettre ensemble toutes ces suggestions. Considérons que nous utilisons une ou
- plusieurs composants PEAR en conjonction avec Zend Framework - par exemple les composants PHPUnit et
- Archive_Tar - et qu'il est occasionnellement nécessaire d'inclure les fichiers relativement au fichier
- courant.</para>
- <para>Premièrement, nous allons créer un dossier pour les librairies dans notre projet. Dans ce même
- dossier, nous allons créer un lien symbolique vers notre dossier Zend Framework
- "<filename>library/Zend</filename>", ainsi que les dossiers nécessaires dans notre installation PEAR
- :</para>
- <programlisting role="php"><![CDATA[
- library
- Archive/
- PEAR/
- PHPUnit/
- Zend/
- ]]></programlisting>
- <para>Ceci nous permet d'ajouter notre propre librairie si nécessaire, tout en laissant intact les
- librairies partagées.</para>
- <para>Ensuite, nous optons pur la création de notre <code>include_path</code> par programme à
- l'intérieur de notre fichier <filename>public/index.php</filename>. Ceci nous permet de déplacer notre
- code dans le système de fichiers, sans devoir éditer l'<code>include_path</code> à chaque fois.</para>
- <para>Nous emprunterons des idées à chacune des suggestions ci-dessus : nous utiliserons les chemins
- absolus, déterminé en utilisant le <code>realpath()</code> ; nous positionnerons Zend Framework au
- plus tôt dans l'<code>include_path</code> ; nous avons déjà vérifié les chemins d'inclusions nécessaires
- ; et nous mettrons le dossier courant comme dernier chemin. En fait, nous faisons tout bien ici - nous
- allons donc terminer avec seulement deux chemins. </para>
- <programlisting role="php"><![CDATA[
- $paths = array(
- realpath(dirname(__FILE__) . '/../library'),
- '.'
- );
- set_include_path(implode(PATH_SEPARATOR, $paths));
- ]]></programlisting>
- </example>
- </sect3>
- </sect2>
- <sect2 id="performance.classloading.striprequires">
- <title>Comment éliminer les déclarations require_once non nécessaires ?</title>
- <para>Le chargement tardif ("lazy loading") est une technique d'optimisation conçue pour repousser l'opération
- coûteuse de chargement d'une classe jusqu'au dernier moment possible - c'est-à-dire lors de l'instanciation d'un
- objet de cette classe, ou lors de l'utilisation d'une constante de classe ou d'une propriété statique. PHP
- supporte tout ceci via l'autoloading (ou "chargement automatique"), ce qui vous permet de définir un ou
- plusieurs callbacks à exécuter dans le but de faire correspondre un nom de classe à un fichier.</para>
- <para>Cependant, la plupart des avantages que vous pourrez retirer de l'autoloading sont diminués si le code de
- votre librairie exécute toujours des appels à <code>require_once</code> - ce qui est précisément le cas de Zend
- Framework. La question est donc : comment éliminer ces déclarations <code>require_once</code> dans le but de
- maximiser les performances de l'autoloader.</para>
- <sect3 id="performance.classloading.striprequires.sed">
- <title>Effacer les appels de require_once avec find et sed</title>
- <para>Une manière simple d'effacer les appels require_once est d'utiliser les utilitaires Unix "find" en
- conjonction avec "sed" pour passe en commentaires tous les appels. Essayez d'exécuter les commandes
- suivantes (où "%" indique le prompteur shell) :</para>
- <programlisting role="shell"><![CDATA[
- % cd chemin/vers/la/librarie/ZendFramework
- % find . -name '*.php' -print0 | xargs -0 \
- sed --regexp-extended --in-place 's/(require_once)/\/\/ \1/g'
- ]]></programlisting>
- <para>Cette ligne unique (coupée en deux pour la lisibilité) itère parmi les fichiers PHP et y remplace
- toute les instances de <code>require_once</code> par <code>//require_once</code>, c'est-à-dire en commentant
- toutes ces lignes.</para>
- <para>Cette commande peut être simplement ajoutée à un script de construction automatique ou à un processus
- de mise en production, permettent ainsi d'augmenter les performances de votre application en production. Il
- est à noter, cependant, que si vous utilisez cette technique, vous <emphasis>devez</emphasis> utiliser
- l'autoloading ; vous pouvez l'activer dans votre fichier <filename>public/index.php</filename> en ajoutant
- le code suivant :</para>
- <programlisting role="php"><![CDATA[
- require_once 'Zend/Loader.php'; // ce require_once reste cependant nécessaire
- Zend_Loader::registerAutoload();
- ]]></programlisting>
- </sect3>
- </sect2>
- <sect2 id="performance.classloading.pluginloader">
- <title>Comment accélérer le chargement des plugins ?</title>
- <para>Certains composants utilisent les plugins, ce qui vous permet de créer vos propres classes afin de les
- utiliser avec le composant, de même que de surcharger les plugins standard existants embarqués dans Zend
- Framework. Ceci fournit une importante flexibilité au framework, mais a un prix : le chargement des plugins est
- une tâche assez coûteuse.</para>
- <para>Le chargeur de plugins vous permet de définir des paires préfixe de classe / chemin, vous autorisant ainsi
- à spécifier des fichiers de classe dans des chemins de dossiers non standard. Chaque préfixe peut avoir de
- multiples chemins associés. En interne, le chargeur de plugins boucle à travers chaque préfixe, et ensuite à
- travers chaque chemin lui étant associé, en testant l'existence du fichier et s'il est accessible dans ce
- chemin. Il le charge ensuite, et teste pour voir si la classe recherchée est bien disponible. Comme vous pouvez
- l'imaginer, tout ceci entraîne des appels aux stats du système de fichiers.</para>
- <para>Multipliez ceci par le nombre de composants qui utilisent le PluginLoader, et vous aurez une idée de
- l'importance de ce problème. Au moment de l'écriture de ce document, les composants suivants utilisent le
- PluginLoader :</para>
- <itemizedlist>
- <listitem>
- <para><classname>Zend_Controller_Action_HelperBroker</classname> : aides d'action</para>
- </listitem>
- <listitem>
- <para><classname>Zend_Dojo</classname> : aides de vues, éléments de formulaires et décorateurs</para>
- </listitem>
- <listitem>
- <para><classname>Zend_File_Transfer</classname> : adaptateurs</para>
- </listitem>
- <listitem>
- <para><classname>Zend_Filter_Inflector</classname> : filtres (utilisé par l'aide d'action
- <code>ViewRenderer</code> et <classname>Zend_Layout</classname>)</para>
- </listitem>
- <listitem>
- <para><classname>Zend_Filter_Input</classname> : filtres et validateurs</para>
- </listitem>
- <listitem>
- <para><classname>Zend_Form</classname> : éléments, validateurs, filtres, décorateurs, captcha et adaptateur pour
- les transferts de fichiers</para>
- </listitem>
- <listitem>
- <para><classname>Zend_Paginator</classname> : adaptateurs</para>
- </listitem>
- <listitem>
- <para><classname>Zend_View</classname> : aides de vues, filtres</para>
- </listitem>
- </itemizedlist>
- <para>Comment réduire le nombre des appels réalisés ?</para>
- <sect3 id="performance.classloading.pluginloader.includefilecache">
- <title>Utiliser le fichier de cache des inclusions du PluginLoader</title>
- <para>Zend Framework 1.7.0 ajoute un fichier de cache des inclusions au PluginLoader. Cette fonctionnalité
- écrit dans un fichier les appels "<code>include_once</code>", que vous pouvez ensuite inclure dans votre
- fichier d'amorçage. Même si ceci introduit de nouveaux appels include_once dans votre code, cela permet de
- s'assurer que le PluginLoader les retournera au plus vite.</para>
- <para>La documentation du PluginLoader <link linkend="zend.loader.pluginloader.performance.example">inclue
- un exemple complet de son utilisation</link>.</para>
- </sect3>
- </sect2>
- </sect1>
- <!--
- vim:se ts=4 sw=4 et:
- -->
|