PHP


Auto chargement automatique des classes

Définition d’un Autoloader

Montre le principe de l’auto chargement des classes en PHP

Lorsqu’un développeur Java commence la programmation objet en PHP et veut utiliser la notion de namespace pour organiser ses projets comme il le ferait avec les package en Java, il peut être dérouté par le fait qu’en PHP la déclaration d’une classe après le mot clé ’use’ (que l’on pourrait comparer à ’import’ en Java) ne sera pas suffisante lorsque qu’il voudra faire référence à un objet dans un fichier. Il devra en plus inclure les fichiers de définitions nécessaires en faisant un ’require’ pour chacun d’eux. Heureusement, pour simplifier la vie du programmeur, PHP propose un système de chargement automatique des classes qui lui évitera ces double déclarations.


 Présentation

Lorsque l’on fait de la programmation objet en PHP, il est conseillé de définir chaque classe dans un fichier séparé. La conséquence de cela est que vous allez vous retrouver avec une grosse quantité de fichiers à gérer et devoir les inclure dans chaque programme utilisant ces classes (require). D’autres part, comme vos fichiers seront nombreux, vous aller les classer dans des sous-répertoires différents et bien sûr, vous utiliserez des espaces de noms ce qui devrait encore complexifier le problème. Voyons dans un premier temps, le principe de l’autoload en PHP.

Remarque : En PHP, contrairement à Java, le langage n’oblige pas à ce que le nom pleinement qualifié d’une classe (espace de nom + nom de la classe) corresponde à l’arborescence des répertoires contenant les fichiers sources. En Java, l’organisation des packages devant correspondre exactement à l’arborescence des fichiers, les EDI   gèrent automatiquement et de manière transparente la correspondance entre les packages et répertoires sans que le programmeur n’ait à s’en préoccuper.

 Principe de l’autoload de PHP

Nous allons d’abord voir un premier programme PHP en mode console. Il sera composé de 3 classes et d’un petit programme de test qui les utilisera. Voici le contenu des différents fichiers :

Fichier : Client.php

  1. <?php
  2.  
  3. class Client
  4. {
  5.   public function __construct()
  6.   {
  7.     echo 'Creation d\'une instance de Client', PHP_EOL;
  8.   }
  9. }

Télécharger

Fichier : Catalogue.php

  1. <?php
  2.  
  3. class Catalogue
  4. {
  5.   public function __construct()
  6.   {
  7.     echo 'Creation d\'une instance de Catalogue', PHP_EOL;
  8.   }
  9. }

Télécharger

Fichier : Produit.php

  1. <?php
  2.  
  3. class Produit
  4. {
  5.   public function __construct()
  6.   {
  7.     echo 'Creation d\'une instance de Produit', PHP_EOL;
  8.   }
  9. }

Télécharger

Fichier : test1.php

  1. <?php
  2.  
  3. require 'Client.php';
  4. require 'Catalogue.php';
  5. require 'Produit.php';
  6.  
  7. $client = new Client();
  8. $catalogue = new Catalogue();
  9. $produit = new Produit();

Télécharger

Si vous exécutez le programme avec la commande suivante :

Vous devriez avoir le résultat suivant :

Si nous supprimons les requires, nous devrions avoir ce genre de message d’erreur suivant :

Nous sommes obligé d’ajouter autant d’inclusions de fichiers qu’il y a de classes utilisées auxquelles il faudra ajouter autant de use quand nous utiliserons des espaces de noms. Voyons déjà comment se passer des inclusions.

PHP fournit un système d’autoload pour éviter d’ajouter les lignes d’inclusions. Pour cela, nous devons :

  1. créer une fonction qui soit capable de déduire le chemin et nom du fichier à partir du nom de sa classe et qui effectuera l’inclusion require correspondant ;
  2. passer le nom de cette fonction à la fonction spl_autoload_register() pour qu’elle soit mise dans une pile d’appel qui permettra à PHP de l’exécuter lorsque ce sera utile.

Définissons d’abord la fonction qui sera chargée de réaliser l’inclusion du fichier à partir de nom de la classe. Dans notre exemple simplifié, cette fonction pourrait être :

  1. function autoload( $className )
  2. {
  3.   require "$className.php";
  4. }

Télécharger

Nous allons maintenant indiquer à PHP qu’il devra exécuter cette fonction s’il ne trouve pas sa déclaration lors de l’exécution du programme, ce qui donne maintenant le code suivant :

  1. <?php
  2.  
  3. function autoload( $className )
  4. {
  5.   require "$className.php";
  6. }
  7.  
  8. spl_autoload_register( 'autoload' );
  9.  
  10. $client = new Client();
  11. $catalogue = new Catalogue();
  12. $produit = new Produit();

Télécharger

Maintenant, quelque soit le nombre de classes que vous utiliserez, vous n’aurez rien d’autre à ajouter, les fichiers seront inclus automatiquement en fonction des besoins.

 Autoloader et espace de nom

Nous venons de voir comment automatiser l’inclusion de nos classes automatiquement. Nous allons voir maintenant comment faire lorsque nous utilisons des espaces de noms et avec des classes se trouvant dans des répertoires différents.

Nous allons modifier l’organisation de notre projet pour qu’il se rapproche un peu d’un projet réel. Nous allons créer un sous-répertoire nommé app dans lequel nous placerons la définition de nos classes. Dans ce répertoire, nous ajouterons autant de sous-répertoire que de domaines composant le projet pour y mettre les fichiers classes. Dans le répertoire app, nous allons également créer un nouveau fichier nommé Autoloader.php qui contiendra la classe définissant l’autoloader pour ces classes. Nous aurons donc l’arborescence suivante :

Nous ajoutons dans nos fichiers de définitions des classes les namespaces correspondant :

Fichier : app/clientele/Client.php

  1. <?php
  2.  
  3. namespace app\clientele;
  4.  
  5. class Client
  6. {
  7.   public function __construct()
  8.   {
  9.     echo 'Creation d\'une instance de Client', PHP_EOL;
  10.   }
  11. }

Télécharger

Fichier : app/produits/Catalogue.php

  1. <?php
  2.  
  3. namespace app\produits;
  4.  
  5. class Catalogue
  6. {
  7.   public function __construct()
  8.   {
  9.     echo 'Creation d\'une instance de Catalogue', PHP_EOL;
  10.   }
  11. }

Télécharger

Fichier app/produits/Produit.php

  1. <?php
  2.  
  3. namespace app\produits;
  4.  
  5. class Produit
  6. {
  7.   public function __construct()
  8.   {
  9.     echo 'Creation d\'une instance de Produit', PHP_EOL;
  10.   }
  11. }

Télécharger

Maintenant, avant de créer la classe Autoloader, nous allons modifier la fonction autoload() pour qu’elle tienne compte de la nouvelle organisation et des espaces de noms. Comme nous utilisons maintenant des espaces de noms, nous devons également ajouter une clause use pour chaque classe utilisée.

Ce qui donne le fichier de test suivant :

  1. <?php
  2.  
  3. function autoload( $className )
  4. {
  5.   $file = str_replace( '\\', DIRECTORY_SEPARATOR, $className );
  6.   require "$file.php";
  7. }
  8.  
  9. spl_autoload_register( 'autoload' );
  10.  
  11. use app\clientele\Client;
  12. use app\produits\Catalogue;
  13. use app\produits\Produit;
  14.  
  15. $client = new Client();
  16. $catalogue = new Catalogue();
  17. $produit = new Produit();

Télécharger

Dans ce cas nous nous sommes contenté de remplacer le caractère ’\’ utilisé par l’espace de nom par le séparateur de répertoire ( ’/’ pour les systèmes UNIX). Nous ajoutons les clauses use pour tenir compte des namespaces.

 Une classe Autoloader

Nous allons maintenant voir comment remplacer notre fonction de téléchargement par une classe pour que le code soit déporté de notre fichier principale et rendre le programme plus modulaire.

Dans le fichier Autoloader.php nous allons créer une classe Autoloader dans laquelle on définit deux méthodes statiques, une qui correspond à la précédente fonction autoload() et une nommée register() qui se charge d’enregistrer la précédente.

  1. <?php
  2.  
  3. namespace app;
  4.  
  5. class Autoloader
  6. {
  7.   static function register()
  8.   {
  9.     spl_autoload_register( array( __CLASS__, 'autoload' ) );
  10.   }
  11.   static function autoload( $className )
  12.   {
  13.     $file = str_replace( '\\', DIRECTORY_SEPARATOR, $className );
  14.     require "$file.php";
  15.   }
  16. }
  17.  

Télécharger

Lors de l’appel de la fonction spl_autoload_register(), nous passons maintenant un tableau pour spécifier le nom de la classe dans laquelle on se trouve pour appeler la méthode. Nous spécifions également en début de fichier l’espace de nom puisque nous avons mis ce fichier dans le dossier app.

Nous avons créés des méthodes statiques pour nous éviter d’avoir à instancier la classe Autoloader.

Remarque : La constante __CLASS__ fait partie des constantes dites "magique" de PHP et contient le nom de la classe courante. Pour plus de renseignements voir ici

Il nous reste à modifier le fichier principal pour remplacer les fonctions par l’utilisation de la classe. Ce qui donne :

  1. <?php
  2.  
  3. require 'app/Autoloader.php';
  4. app\Autoloader::register();
  5.  
  6. use app\clientele\Client;
  7. use app\produits\Catalogue;
  8. use app\produits\Produit;
  9.  
  10. $client = new Client();
  11. $catalogue = new Catalogue();
  12. $produit = new Produit();

Télécharger

Nous appelons la méthode statique register() mais comme l’autoload n’est pas encore défini nous devons, inclure le fichier avec un require.

Dans cet exemple, nous avons fait correspondre exactement l’organisation des espaces de noms et des répertoires, ce qui permet d’avoir une fonction autoload très simple mais comme PHP n’impose pas de règles vous pourriez vous retrouver avec une organisation plus complexe surtout si vous utilisez dans votre projet des librairies développées par d’autres développeurs.

  Propose a Standards Recommendation ou PSR

Dans un but d’homogénéiser les projet PHP et faciliter l’interopérabilité entre les différents framework, des organismes proposent des recommandations de codages. Il y en a une reconnue aujourd’hui dans le monde PHP pour l’organisation des espaces de noms qui se nomme PSR-4.

Vous trouverez ici un exemple de code d’auto chargement pour une organisation d’espace de noms respectant cette recommandation PSR-4.

 Conclusion

Nous venons de voir une méthode pour inclure automatiquement les fichiers définissant les classes basée sur la fonction spl_autoload_register() dans des cas simple. Dans un véritable projet, il est conseillé d’utiliser Composer, un outil de gestion de dépendances qui vous permettra d’ajouter et gérer les librairies utiles à votre développement. Il vous permettra aussi de gérer proprement l’auto chargement de vos classes et vous permettra de respecter la fameuse PSR-4 de manière simple. Ce sera le sujet d’un autre article.


Article n° 142

Crée par: chris

Créé le: 16 septembre

Modifié le: 16 septembre

Nombre de visites: 9

Popularité: 7 %

Popularité absolue: 1

Mots clés de cet article


SPIP

2003-2019 LePpf
Plan du site | | Contact | RSS 2.0

Visiteurs connectés : 3

Nombre moyen de visites quotidiennes sur le site: 203