Zend Framework - Optimisation des performances, exemple
Voici un petit exemple d'optimisation réalisé. J'ai analysé avec XDebug et WinCacheGrind l'appel à une page. Cette page affiche quelques centaines de lignes provenant d'une table d'une base de données.
Chacune des lignes est affichée avec un partial ce qui me permet d'utiliser le même affichage dans deux pages différentes. Les données de chaque ligne sont accédées via les getters et setters de Zend_Db_Table_Row et Zend_Db_Table_Rowset.
Voici tout d'abord l'analyse de la page sans aucune optimisation.
On constate un temps d'exécution de 488ms. En rouge, j'ai surligné les processus liés aux getters et en jaune ceux liés aux partials. On peut constaté d'ores et déjà qu'ils sont nombreux et au sommet des processus les plus consommateurs.
Voici, ensuite, le résultat après suppression des getters en utilisant des tableaux PHP standard à la place d'objet Zend.
On est passé de 488ms d'exécution à 379ms. Un gain de l'ordre de 20%.
Ci-dessous, la même analyse après l'optimisation des partials et l'utilisation d'includes.
Là, on gagne presque 30% de performance en passant à 225ms de temps d'exécution. Ce qui fait, au total, 50% de gain par rapport au code original.
Voici un petit code qui vous aidera à récupérer le chemin vers vos fichiers de script et donc utiliser un include à la place du helper partial :
$moduleDir = Zend_Controller_Front::getInstance()
->getControllerDirectory('default');
$viewsDir = dirname($moduleDir) . '/views/scripts';
<?include($viewsDir . '/controller/_partial.phtml')?>
Bien entendu, on peut discuter de la manière de faire. Mais ce que j'essaie de démontrer est plutôt la lourdeur des tâches réalisées par Zend. Par exemple, on constate le chargement des plugins, le clonage des variables de la vue, le chargement des helpers, etc... à chaque utilisation de partial()
A utiliser, donc, avec parcimonie et toujours préférer les méthodes efficaces sur des codes récurrents.





Fil des commentaires de ce billet
Commentaires
Très heureux de voir que tu repost sur le ZF
Très heureux d'être suivi de si près.
J'étais pas mal occupé ces temps. Et je dois bien avouer que j'ai même pas eu le temps de travailler sur les nouvelles versions du framework.
Mais je vais m'y remettre, promis !
Bonjour,
dans la doc de Zend, ils disent effectivement de n'utiliser les partials que lorsqu'on en a vraiment besoin, c'est à dire quand on veut un espace de noms tout propre pour les variables utilisées dans le fichier phtml.
Le reste du temps, un render() fait l'affaire. Je suppose que ce n'est toujours pas aussi performant qu'un include mais ça doit s'en approcher.
A noter aussi, si on doit répéter un partial dans une page, il vaut mieux utiliser partialLoop() qui ne fait les inits qu'une fois pour toutes les itérations.
Personnellement, je n'ai pas encore trouvé d'utilité à partial() mais partialLoop() me sert parfois pour son partialCounter.
Désolé pour le double post, je nettoyais mon texte et le coup est parti tout seul.
Je tenais à vous remercier pour les infos disponibles sur ce blog, elles sont claires et utiles.
Pas mal cet article, je ferais bien de m'y mettre aussi à l'analyse des performances avant que mon appli devienne trop grosse.
Eric, je te rejoins sur le terrain du blog sur ZF : http://mpp.selfip.com/
Un site réalisé par mes soins avec ZF, Smarty, Doctrine et Mootools. Pour ZF je me suis inspiré de certaines de tes techniques donc merci beaucoup
A bientôt !
Bonjour,
Effectivement comme tout Framework, que se soit ZendFramework, Symfony, CackePHP et j'en passe... la performance n'est pas souvent au rendez-vous, car ces frameworks sont fondés sur une structure MVC et un ORM parfois lourd.
Ta solution pour réduire le temps d'exécution au niveau des objets Zend_Db_Table qui est d'utiliser toArray() est parfois bonne mais dans la plupart des cas c'est se priver de l'avantage de travailler avec des objets. La plupart du temps dans mes développement, je crée mon propre RowClass pour lui ajouter des méthodes. Donc dans ma vue ou dans mon controller je peux faire par exemple quand je boucle sur un objet de type Rowset un $oRow->getMaMéthode(); ce que tu ne peux pas faire si tu travailles avec des tableaux.
Il vaut mieux se pencher sur une bonne utilisation du Cache pour éviter les requêtes / ou fonctions trop gourmandes.