Les Autoloaders
Présentation
Un autoloader est un mécanisme qui permet de charger automatiquement les Classes lorsqu'elles sont solicitées, évitant ainsi la nécessité d'importer manuellement chacune d'elles avant de l'utiliser. Cela facilite la gestion des dépendances et améliore la structure du code en chargeant dynamiquement les classes au moment de leur utilisation.
Lorsqu'une Classe est utilisée pour la première fois, l'autoloader est automatiquement appelé. Il convertit alors le chemin de l'espace de nom en un chemin de fichier et l'inclut automatiquement dans le code.
Cette approche permet d'éviter de surcharger le code avec des informations redondantes lorsqu'on utilise l'instruction use, en éliminant la nécessité d'ajouter manuellement des fonctions d'importation telles que require_once() ou import_once():
<?php
use Core\{
GestionVue,
GestionFormulaire,
GestionMessage
};
/*
Avec l'utilisation de l'autoloader, pour importer les Classes désirées, l'utilisation seule de l'instruction "use" suffit.
Les lignes suivantes ne sont donc plus nécessaires :
require_once dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'core' . DIRECTORY_SEPARATOR . 'gestion_vue.php';
require_once dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'core' . DIRECTORY_SEPARATOR . 'gestion_formulaire.php';
require_once dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'core' . DIRECTORY_SEPARATOR . 'gestion_message.php';
*/
?>
Pour profiter d'un Autoloader, il vous suffit de définir les namespaces racines en accord avec la structure des chemins des fichiers de votre projet, puis d'appeler la fonction d'initialisation au début de votre script.
Installation
Même si la création d'un Autoloader peut s'avérer amusante et ne requiert pas des compétences techniques avancées, plusieurs solutions sont disponibles via Composer. Composer est un gestionnaire de dépendances pour les projets PHP, simplifiant le processus de gestion, d'installation et de mise à jour des bibliothèques et packages nécessaires à un projet. Si vous n'avez pas encore installé Composer, vous le télécharger le fichier "Composer-Setup.exe" sur le site officiel et suivre la procédure d'installation une fois ce fichier exécuté.
Installer l'Autoloader de Composer :
- Ouvrez le terminal et assurez vous d'être à la racine de votre projet.
- Initialiser Composer pour votre projet en exécutant la commande suivante : composer init.
- Répondez aux questions qui vous sont posées (si la proposition qui vous est faite vous convient, il vous suffit de cliquer sur "Enter") :
- Nom du package (nom du projet) : Vous devrez fournir un nom pour votre projet. Il est généralement au format "vendor/nom-du-projet", par exemple "monentreprise/mon-projet".
- Description : Une description optionnelle de votre projet.
- Nom de l'auteur : Votre nom, ou le nom de l'auteur du projet.
- Stabilité minimale : LA stabilité minimale fait référence au niveau de stabilité des versions des packages (bibliothèques, composants, etc.) que Composer doit installer pour votre projet :
- Stable (option par défaut) : Versions considérées comme stables et adaptées à une utilisation en production.
- RC (Release Candidate) : Versions candidates à une publication stable, mais qui nécessitent des tests approfondis.
- Beta : Versions avec des fonctionnalités complètes, mais susceptibles de contenir des bugs.
- Alpha : Versions partiellement complètes et pouvant contenir des changements importants.
- Dev : Version en cours de développement directement depuis la branche principale ou une branche spécifique.
- Type de projet : Vous pouvez spécifier le type de votre projet (par exemple, "library", "project", "metapackage", etc.). En spécifiant le type de projet, Composer peut adapter son comportement en conséquence. Par exemple, un projet de type "library" peut être destiné à être utilisé comme dépendance dans d'autres projets, tandis qu'un projet de type "project" est généralement une application autonome. Utiliser correctement le type de projet peut aider à organiser et à structurer votre projet, ainsi qu'à informer Composer sur la manière de traiter votre code lors de l'installation et de la mise à jour des dépendances.
- library : Utilisé pour déclarer un projet PHP en tant que bibliothèque réutilisable.
- project : Utilisé pour déclarer un projet PHP en tant que projet d'application ou projet principal.
- metapackage : Utilisé pour déclarer un package qui ne fournit pas de code exécutable, mais plutôt des dépendances pour composer d'autres packages.
- composer-plugin" : Utilisé pour déclarer un package comme un plugin Composer, étendant les fonctionnalités de Composer lui-même.
- Autres types personnalisés : Vous pouvez également définir des types personnalisés pour spécifier la nature particulière de votre projet.
- Licence : Vous pouvez choisir une licence pour votre projet :
- MIT : Une licence permissive qui permet presque tout, tant que la notice de copyright et la licence sont incluses dans toutes les copies ou des parties substantielles du logiciel.
- GPL (GNU General Public License) : Une licence copyleft qui impose certaines conditions, notamment que toute œuvre dérivée du logiciel original doit également être sous licence GPL.
- Apache 2.0 : Une licence permissive qui permet l'utilisation du logiciel à des fins privées ou commerciales, ainsi que la création d'œuvres dérivées sous une licence différente.
- BSD : Une famille de licences permissives qui permettent une grande liberté d'utilisation, de modification et de distribution.
- proprietary : Un logiciel avec une licence propriétaire, généralement soumis à des restrictions plus strictes sur son utilisation, sa modification et sa distribution.
- Configurer les dépendances automatiquement ? (yes/no) : Vous pouvez choisir de configurer vos dépendances maintenant ou le faire plus tard manuellement dans le fichier "composer.json".
Une fois l'autoloader installé, vous devez l'importer au début de votre script principal. Dans l'exemple suivant, nous importons l'autoloader dans le fichier "index.php" situé dans le dossier "public".
projet/
|-- public/
| |-- index.php
|-- vendor/
| |-- autoloader.php
|-- composer.json
<?php
// fichier : public/index.php
require dirname(__DIR__) . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';
// ...
?>
Il vous suffit maintenant de configurer l'autoloader dans le fichier "composer.json".
Configuration
Les autoloaders en PHP, tels que ceux conformes aux spécifications PSR-0, PSR-4, ou d'autres mécanismes personnalisés, doivent être configurés pour fonctionner correctement. La configuration d'un autoloader consiste généralement à indiquer à PHP où trouver les fichiers en faisant correspondre des "namespaces" racine à une structure de dossiers. Vous n'avez donc pas besoin de configurer l'autoloader individuellement pour chaque classe. L'objectif d'un autoloader est de charger automatiquement les classes lorsqu'elles sont utilisées, sans que vous ayez à spécifier manuellement chaque fichier de classe.
Dans l'exemple ci-dessous, la configuration de l'autoloader est basée sur le modèle fourni par le gestionnaire de dépendances "Composer". Dans ce fichier, une correspondance est établie entre le dossier "app/" et le namespace "App\", ainsi qu'entre le dossier "core/" et le namespace "Core\". Ces dossiers sont tous deux localisés à la racine du projet. Dans le cas de l'autoloader de composer, le fichier de configuration se situe à la racine du projet et se nomme "composer.json" :
{
...
...
"autoload":
{
"psr-4":
{
"App\\": "app/",
"Core\\": "core/"
}
}
}
On peut aussi isoler tous les namespaces dans un namespace parent commun :
{
...
...
"autoload":
{
"psr-4":
{
"MonApp\\App\\": "app/",
"MonApp\\Core\\": "core/"
}
}
}
Il est possible d'attribuer un même namespace à plusieurs chemins. Dans l'exemple suivant, les dossiers "app/" et "core/" situés à la racine du projet sont représentés par le namespace "MonApp\" :
{
...
...
"autoload":
{
"psr-4":
{
"MonApp\\": ["app/", "core/"]
}
}
}
Après avoir apporté des modifications à la configuration de l'autoloader, assurez-vous de mettre à jour celui-ci en utilisant la commande suivante dans le terminal : composer dump-autoload.
La Norme PSR-4
Le PSR-4 (PHP Standard Recommendation 4) est une recommandation du groupe PHP-FIG qui définit une norme pour l'autoloading des Classes en PHP. Cette norme spécifie une convention de nommage des Classes et des espaces de noms, facilitant l'utilisation d'un autoloader conforme à cette norme, comme celui fourni par Composer.
Avec la norme PSR-4, les espaces de noms et les Classes sont directement liés à la structure des répertoires. Par exemple, si votre espace de noms est "App\Controllers", les Classes appartenant à cet espace de noms seront situées dans un répertoire similaire à "App/Controllers".
Voici une traduction des règles de la norme PSR-4 telles quelles sont présentées sur le site PHP-FIG :
- Cette PSR décrit une spécification pour le chargement automatique des Classes à partir des chemins de fichiers. Elle est entièrement interopérable et peut être utilisée en complément de toute autre spécification de chargement automatique, y compris la PSR-0. Cette PSR décrit également l'emplacement des fichiers qui seront chargés automatiquement selon la spécification.
- Le terme "Classe" se réfère aux Classes, interfaces, traits et autres structures similaires. Un nom de classe entièrement qualifié a la forme suivante :
-
\<NamespaceName>(\<SubNamespaceNames>)*\<ClassName> - Le nom de Classe entièrement qualifié DOIT avoir un nom d'espace de niveau supérieur, également appelé "espace de noms du fournisseur".
- Le nom de Classe entièrement qualifié PEUT avoir un ou plusieurs noms de sous-espaces de noms.
- Le nom de Classe entièrement qualifié DOIT avoir un nom de Classe terminal.
- Les traits d'union bas n'ont aucune signification particulière dans aucune partie du nom de Classe entièrement qualifié.
- Les caractères alphabétiques dans le nom de Classe entièrement qualifié PEUVENT être une combinaison de minuscules et de majuscules.
- Tous les noms de Classe DOIVENT être référencés de manière sensible à la casse.
-
- Lors du chargement d'un fichier correspondant à un nom de Classe entièrement qualifié :
- Une série continue d'un ou plusieurs noms d'espace de noms principaux et de sous-noms d'espace de noms, à l'exclusion du séparateur de nom d'espace de début, dans le nom de Classe entièrement qualifié (un "préfixe d'espace de noms") correspond à au moins un "répertoire de base".
- Les sous-noms d'espace de noms continus après le "préfixe d'espace de noms" correspondent à un sous-répertoire dans un "répertoire de base", où les séparateurs de noms d'espace représentent les séparateurs de répertoire. Le nom du sous-répertoire DOIT correspondre à la casse des noms de sous-espaces de noms.
- Le nom de Classe terminal correspond à un nom de fichier se terminant par .php. Le nom de fichier DOIT correspondre à la casse du nom de Classe terminal.
- Les implémentations des chargeurs automatiques NE DOIVENT PAS déclencher d'exceptions, NE DOIVENT PAS générer d'erreurs de quelque niveau que ce soit et NE DEVRAIENT PAS renvoyer de valeur.
Fonctionnement d'un Autoloader
Voici à quoi peut ressembler le code d'un Autoloader :
<?php
class Autoloader
{
private static $config;
public static function init(): void
{
self::charger_config();
self::enregistrer();
}
private static function charger_config(): void
{
$config = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'config.json';
self::$config = json_decode(file_get_contents($config), true)['autoloader'];
}
private static function enregistrer(): void
{
// La fonction "spl_autoload_register()" est utilisée pour enregistrer des fonctions d'autoload personnalisées.
// Cette fonction est exécutée lorsqu'une Classe est appelée pour la première fois.
// On lui passe un tableau en paramètre avec la Classe et la méthode devant être appelées pour gérer le chargement de la Classe.
// (La constante magique "__CLASS__" renvoie le nom de la classe dans laquelle elle est utilisée.)
// En résumé, lorsqu'une Classe est appelée pour la première fois, la fonction "spl_autoload_register()" est automatiquement exécutée,
// ensuite, la méthode "charger" de la Classe actuelle (Autoloader) est lancée et le contenu du "use" déclancheur lui est passé en paramètre.
spl_autoload_register([__CLASS__, 'charger']);
}
private static function charger(string $namespaceDeClasse): void
{
// Parcourir toutes les correspondances "namespace / chemin" du fichier de configuration :
foreach (self::$config as $namespaceConfig => $chemins)
{
// Si le namespace présent dans la configuration est trouvé en première position du namespace de la Classe :
if (strpos($namespaceDeClasse, $namespaceConfig) === 0)
{
// Vérifier s'il existe plusieurs chemins pour un même namespace. Si le chemin de configuration est unique, le placer dans un tableau.
$chemins = is_string($chemins) ? [$chemins] : $chemins;
// Parcourir les chemins :
foreach ($chemins as $chemin)
{
// Convertir le namespace par le chemin vers le fichier de la Classe visée :
$cheminFichier = self::convertirNamespaceEnCheminFichier($namespaceConfig, $chemin, $namespaceDeClasse);
// Vérifier si le fichier contenant la Classe existe :
if (file_exists($cheminFichier))
{
// Importer la Classe.
include_once $cheminFichier;
// Sortir des deux boucles.
break 2;
}
}
}
}
}
private static function convertirNamespaceEnCheminFichier(string $namespaceConfig, string $chemin, string $namespaceDeClasse): string
{
// Remplacer du namespace de la Classe par le chemin correspondant présent dans le fichier de configuration.
$nomDeClasse = str_replace($namespaceConfig, $chemin, $namespaceDeClasse);
// Convertir le chemin relatif vers le fichier en chemin absolu.
$cheminFichier = dirname(__DIR__) . DIRECTORY_SEPARATOR . $nomDeClasse . '.php';
// Remplacer les "/" par "DIRECTORY_SEPARATOR" pour s'assurer de la compatibilité.
$cheminFichier = str_replace('/', DIRECTORY_SEPARATOR, $cheminFichier);
return $cheminFichier;
}
}
?>
- Pour initialiser l'Autoloader, la méthode Autoloader::init() doit être appelée en début de script. En premier lieu, elle charge le fichier de configuration de l'Autoloader et exécute la fonction spl_autoload_register().
- La fonction spl_autoload_register() occupe une place centrale dans le fonctionnement de l'Autoloader. Elle permet d'exécuter automatiquement la fonction de traitement qui lui est passée en paramètre chaque fois qu'une classe est appelée pour la première fois. De plus, lors de l'appel de cette fonction de traitement, le namespace de la classe à charger lui est transmis en paramètre.
- La fonction Autoloader::charger() joue le rôle de fonction de traitement dans l'Autoloader. Lorsqu'une classe est sollicitée pour la première fois, cette fonction est automatiquement exécutée, recevant en paramètre le namespace complet de la classe concernée. Elle vérifie ensuite si le namespace racine de la classe correspond à l'un des namespaces configurés dans le fichier de configuration. En cas de correspondance, elle convertit le namespace en un chemin vers le fichier de la classe, suivant les normes établies (par exemple, psr-4). Enfin, elle importe la classe à partir du chemin ainsi généré.
Exercice : Projet Progressif 10
Bonus (facultatif)
- Objectif : Installer et configurer un autoloader pour charger automatiquement vos classes, afin de simplifier l'organisation et la maintenance du projet.
- Instructions :
- Poursuivre le projet progressif initié lors du chapitre sur les modèles de pages dynamiques.
- Installez ou configurez un autoloader qui gérera automatiquement le chargement de vos classes.
- Testez l'autoloader en utilisant des classes de différents namespaces pour vérifier que tout se charge correctement sans avoir recours à des require_once manuels.