Une application se compose de nombreuses classes PHP et chaque classe réside généralement dans un fichier distinct. Cela introduit le besoin d'inclure les fichiers.
Par exemple, supposons que nous ayons le fichier Application.php qui contient la définition de la classe
\Zend\Mvc\Application
de la section précédente. Avant de pouvoir créer une instance de la classe
Application
quelque part dans votre code, vous devez inclure le contenu du fichier Application.php
(vous pouvez le faire à l'aide de l'instruction require_once
en lui passant le chemin d'accès complet
au fichier) :
<?php
require_once "/path/to/zendframework/zend-mvc/src/Application.php";
use Zend\Mvc\Application;
$application = new Application();
Au fur et à mesure que votre application augmente en taille, il peut être difficile d'inclure chaque fichier nécessaire. Zend Framework 3 lui-même se compose de centaines de fichiers, et il peut être très difficile de charger la bibliothèque entière et toutes ses dépendances de cette façon. De plus, lors de l'exécution du code résultant, l'interpréteur PHP prendra du temps CPU pour traiter chaque fichier inclus, même si vous ne créez pas une instance de ladite classe.
Pour résoudre ce problème, en PHP, une fonctionnalité de chargement automatique de classe a été introduite.
La fonction PHP spl_autoload_register()
vous permet de créer une fonction d'autoloading (chargement automatique).
Pour les sites complexes, vous pouvez même créer plusieurs fonctions de chargement automatique, qui sont
chaînées dans une pile.
Pendant l'exécution du script, si l'interpréteur PHP rencontre un nom de classe qui n'a pas encore été défini, il appelle la ou les autoloaders déclarées jusqu'à ce qu'il y en est un qui trouve la classe ou que l'erreur "not found" soit levée. Cela permet un chargement "lazy" (paresseux), l'interpréteur PHP ne traite la définition de la classe qu'au moment de l'appel de cette classe, ie, quand cela est vraiment nécessaire.
Pour vous donner une idée de la façon dont une fonction d'autoloading se présente, voyons ci-dessous une implémentation simplifiée d'une fonction d'autoloading :
<?php
// Autoloader function.
function autoloadFunc($className)
{
// Mappage des classes dans un tableau statique.
static $classMap = [
'\\Zend\\Mvc\\Application' => '/path/to/zendframework/zend-mvc/src/Zend/Mvc/Application.php',
'\\Application\\Module' => '/path/to/app/dir/module/Application/Module.php',
//...
];
// Vérifie si un tel nom de classe est présent dans la class map.
if(isset(static::$classMap[$className])) {
$fileName = static::$classMap[$className];
// Vérifie si le fichier existe et est lisible.
if (is_readable($fileName)) {
// Inclus le fichier.
require $fileName;
}
}
}
// Déclaration de la function d'autoloading
spl_autoload_register("autoloadFunc");
Dans l'exemple ci-dessus, nous définissons la fonction de chargement automatique autoloadFunc()
que nous désignerons sous le nom de class map d'autoloader.
L'autoloader de class map utilise le mappage de classe pour mapper le nom de classe et le chemin absolu vers le fichier PHP contenant cette classe. La class map est juste un tableau PHP contenant des clés et des valeurs. Pour déterminer le chemin d'accès au fichier par nom de classe, l'autoloader de la classe doit simplement extraire la valeur du tableau de class map. Il est évident que l'autoloader de class map fonctionne très vite. Cependant, le désavantage est que vous devez maintenir la class map et la mettre à jour à chaque fois que vous ajoutez une nouvelle classe à votre programme.
Comme chaque fournisseur de bibliothèque utilise ses propres conventions de nommage et d'organisation de fichier, vous devrez enregistrer une fonction de chargement automatique personnalisée différente pour chaque bibliothèque dépendante, ce qui est plutôt ennuyeux. Pour résoudre ce problème, la norme PSR-4 a été introduite.
PSR signifie PHP Standards Recommendation.
La norme PSR-4 définit la structure de code recommandée qu'une application ou une bibliothèque doit suivre pour garantir l'interopérabilité de l'autoloader. En deux mots, la norme dit que :
Les espaces de noms doivent être organisés de la manière suivante :
\<Vendor Name>\(<Namespace>)*\<Class Name>
Les espaces de noms peuvent avoir autant de niveaux d'imbrication que vous le souhaitez, mais le nom du fournisseur (vendor) doit correspondre au niveau supérieur.
Les espaces de noms doivent correspondre à la structure du répertoire. Chaque séparateur d'espace de
noms ('\') est converti en une constante DIRECTORY_SEPARATOR
spécifique au système d'exploitation
lors du chargement à partir du système de fichiers.
Le nom de la classe est suffixé avec l'extension .php lors du chargement du fichier à partir du système de fichiers.
Par exemple, pour la classe Zend\Mvc\Application
,
vous aurez la structure de répertoire suivante :
/path/to/zendframework/zend-mvc/src
/Zend
/Mvc
Application.php
L'inconvénient de ceci est que vous devez mettre votre code dans plusieurs répertoires imbriqués (Zend et Mvc).
Pour résoudre ce problème, le PSR-4 vous permet de définir une série contiguë d'un ou plusieurs namespaces
et sous-namespaces correspondants à un "répertoire de base". Par exemple, si vous avez le nom de classe
complet \Zend\Mvc\Application
, et si vous définissez que \Zend\Mvc
correspond au répertoire
"/path/to/zendframework/zend-mvc/src", vous pouvez organisez vos fichiers comme suit:
/path/to/zendframework/zend-mvc/src
Application.php
Pour le code soit conforme à la norme PSR-4, nous pouvons écrire et déclarer un autoloader, que nous appellerons l'autoloader "standard" :
<?php
// Fonction de chargement automatique "Standard".
function standardAutoloadFunc($className)
{
// Remplace le préfixe du namespace par le répertoire de base.
$prefix = '\\Zend\\Mvc';
$baseDir = '/path/to/zendframework/zend-mvc/src/';
if (substr($className, 0, strlen($prefix)) == $prefix) {
$className = substr($className, strlen($prefix)+1);
$className = $baseDir . $className;
}
// Remplace les séparateurs d'espace de noms dans le namespace par des séparateurs de répertoire.
$className = str_replace('\\', DIRECTORY_SEPARATOR, $className);
// Ajoute l'extension .php.
$fileName = $className . ".php";
// Vérifie si le fichier existe et est lisible.
if (is_readable($fileName)) {
// Inclus le fichier.
require $fileName;
}
}
// Déclaration de la fonction d'autoloader.
spl_autoload_register("standardAutoloadFunc");
L'autoloader standard fonctionne comme suit. En supposant que le namespace des classes peut être mappé à
la structure des répertoires un par un, la fonction calcule le chemin vers le fichier PHP en transformant
les back-slashes (séparateurs de namespace) en forward slashes (séparateurs de chemin) et en concaténant
le chemin d'accès absolu au dossier où se trouve la bibliothèque.
Ensuite, la fonction vérifie si un tel fichier PHP existe vraiment, et si oui, l'inclut avec l'instruction
require
.
Il est évident que l'autoloader standard fonctionne plus lentement que l'autoloader de class map. Cependant, son avantage est que vous n'avez pas besoin de gérer une class map, ce qui est très pratique lorsque vous développez un nouveau code et ajoutez de nouvelles classes à votre application.
Zend Framework 3 est conforme à la norme PSR-4, ce qui permet d'utiliser un mécanisme d'autoloading standard sur tous ses composants. Il est également compatible avec d'autres librairies conformes au PSR-4 comme Doctrine ou Symfony.
Composer peut générer des fonctions d'autoloading (à la fois des autoloaders de class map et des
autoloader norme PSR-4) pour le code que vous installez avec.
Zend Framework 3 utilise l'autoloader fournie par Composer.
Lorsque vous installez un package avec Composer, il crée automatiquement le fichier
APP_DIR/vendor/autoload.php, qui utilise la fonction PHP spl_autoload_register()
pour déclarer
un autoloader. De cette façon, toutes les classes PHP situées dans le répertoire APP_DIR/vendor
sont chargées automatiquement.
Pour charger automatiquement les classes PHP situées dans vos propres modules (comme le module Application
),
vous devez spécifier la clé autoload
dans votre fichier composer.json
:
"autoload": {
"psr-4": {
"Application\\": "module/Application/src/"
}
},
Ensuite, la seule chose à faire est d'inclure ce fichier dans votre script d'entrée index.php
:
// Composer autoloading
include __DIR__ . '/../vendor/autoload.php';
Le fichier autoload.php est généré chaque fois que vous installez un package avec Composer. Au besoin, pour que Composer génère le fichier autoload.php, vous pourrez exécuter la commande
dump-autoload
:
php composer.phar dump-autoload
Dans Zend Skeleton Application, vous pouvez voir comment la norme PSR-4 est appliquée dans la pratique.
Pour le module par défaut de votre site Web, le module Application
, les classes PHP déclarées avec
l'autoloader standard sont stockées dans le répertoire APP_DIR/module/Application/src
("src" abréviation
de "source").
Nous ferons référence au répertoire
src
en tant que répertoire source du module.
Par exemple, regardons le fichier IndexController.php
du module Application
(figure 3.2).
Comme vous pouvez le voir, il contient la classe IndexController
1 appartenant à l'espace de
noms Application\Controller
. Pour pouvoir suivre la norme PSR-4 et utiliser l'autoloader standard avec
cette classe PHP, nous devons le placer dans le dossier Controller
du dossier source du module.
1) La classe IndexController
est le contrôleur par défaut de l'application squelette.
Nous parlerons des contrôleurs plus loin dans le chapitre Model-View-Controller.