Zend Framework

Optimiser Zend – Partie 1

Cela fait un moment que je ne vous ai pas refait de tutoriaux pour le Framework Zend. Aujourd’hui je vous propose une adaptation d’un tutoriel en anglais que l’on m’avait fait parvenir et qui m’a grandement aidé (malheureusement, il n’est plus sur la toile).

Vous savez comme moi que l’un des points faibles de Zend Framework, c’est la performance, il est beaucoup plus lent que du PHP objet de base du fait de la majeur partie des classes qui sont chargées lors du lancement d’une page. Je vais donc réaliser ce tutoriel en plusieurs parties.

Aujourd’hui, je vais juste vous expliquer comment diminuer les chargements inutiles et redéfinir le fichier d’amorçage (le fameux index.php). Vous vous souvenez tous comment est composé le fichier index.php ? Et bien voici un petit rappel pour ceux qui ne savent pas :
/**
* Fichier index.php permettant de lancer le bootstrap
*
*/

//Définition du chemin vers le dossier application
defined('APPLICATION_PATH')
|| define('APPLICATION_PATH',
realpath(dirname(__FILE__) . '/../application'));

//Définition de la variable de d'application (utile pour les fichiers de configuration
defined('APPLICATION_ENV')
|| define('APPLICATION_ENV',
(getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV')
: 'production'));

//Partie permettant d'inclure les différentes librairies
//du dossier library (en théorie).
//Nécessite un complément côté bootstrap.
set_include_path(implode(PATH_SEPARATOR, array(
dirname(dirname(__FILE__)) . '/library',
get_include_path(),
)));

/** Zend_Application */
require_once 'Zend/Application.php';

// Créer l'application, le bootstrap et démarre
$application = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH . '/configurations/app.ini'
);
$application->bootstrap()
->run();

Nous allons juste ajouter une petite partie permettant d’inclure plus rapidement les classes de Zend en repassant par Zend_Autoloader et nous redéfinirons sa méthode d’inclusion. Voici donc le nouveau index.php qui vous parlera mieux que mes explications :
// Define path to application directory
defined('APPLICATION_PATH')
|| define('APPLICATION_PATH',
realpath(dirname(__FILE__) . '/../application'));

// Define application environment
defined('APPLICATION_ENV')
|| define('APPLICATION_ENV',
(getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV')
: 'production'));

// Typically, you will also want to add your library/ directory
// to the include_path, particularly if it contains your ZF install
set_include_path(implode(PATH_SEPARATOR, array(
dirname(dirname(__FILE__)) . '/library',
get_include_path(),
)));

//redéfinition de l'autoloader par défaut afin d'optimiser le chargement
require_once 'Zend/Loader/Autoloader.php';
$autoloader = Zend_Loader_Autoloader::getInstance();
$autoloader->setDefaultAutoloader(create_function('$class',
"include str_replace('_', '/', \$class) . '.php';"
));

/** Zend_Application */
//require_once 'Zend/Application.php';

// Create application, bootstrap, and run
$application = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH . '/configurations/app.ini'
);
$application->bootstrap()
->run();

Cette partie ne suffit pas, pour gagner encore du temps, je vous invite à suivre le conseil donné par l’équipe Zend en fin de documentation, à savoir, supprimer tous les require_once inutiles de la bibliothèque Zend. (je vous invite aussi à les enlever de vos controller, formulaires, …).

En effet, pour chaque require_once, le serveur va effectuer des accès disque et c’est ces accès disques qui ralentissent le serveur. La méthode est donc de les enlever et ensuite, notre redéfinition faite dans le index.php prendra le relais, elle effectuera tardivement le chargement de tous les fichiers nécessaires afin d’optimiser le chzrgement de nos classes. La documentation Zend explique mieux que moi cette partie:

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.

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 à require_once – ce qui est précisément le cas de Zend Framework. La question est donc : comment éliminer ces déclarations require_once dans le but de maximiser les performances de l’autoloader.

Pour ce faire, il ne vous suffit que d’exécuter cette commande sous Linux (je rajouterai celle sous Windows et FreeBSD quand je les aurais retrouvé) :
% 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'

Pour finir, nous définissons une nouvelle fonction dans notre Bootstrap principal afin que lui aussi tire parti de ces changements :
public static function autoload($class)
{
include str_replace('_', '/', $class) . '.php';
return $class;
}

Voilà, après ces quelques modifications, votre site devrait se charger un poil plus vite et consommer moins de mémoires.

Dans la seconde partie, je vous expliquerai comment créer une méthode qui mesure la charge mémoire de chacune de vos pages. Si vous avez des questions, des remarques, des critiques ou même des corrections, n’hésitez pas à me les faire parvenir.