| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- EN-Revision: 24249 -->
- <!-- Reviewed: no -->
- <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 language="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 language="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 language="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 language="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 language="shell"><![CDATA[
- % cd chemin/vers/la/librarie/ZendFramework
- % find . -name '*.php' -not -wholename '*/Loader/Autoloader.php' \
- -not -wholename '*/Application.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 (tout
- en maintenant les appels à <function>require_once</function> dans
- <classname>Zend_Application</classname> et
- <classname>Zend_Loader_Autoloader</classname>, puisque ces classes tomberont en
- erreur sans ceux-ci).
- </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 language="php"><![CDATA[
- require_once 'Zend/Loader/Autoloader.php';
- Zend_Loader_Autoloader::getInstance();
- ]]></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>
|