Chargement automatique de classes avancé avec PHP 5 Des implémentations plus ou moins complexes possibles

On peut imaginer une implémentation sommaire sous cette forme :

   1.  <?php
  2.   define('CLASSES_DIR', 'myproject/classes');
  3.      
  4.   function __autoload($classname)
  5.   {
  6.   require(CLASSES_DIR.'/class.'.$classname.'.php');
  7.   }


Ouf, du code ! Ici, on fait en sorte que pour une classe MyClass, PHP charge le fichier myproject/classes/class.MyClass.php, qui devrait, le cas échéant, contenir la définition de MyClass. C'est bien, mais encore un peu light dès qu'on cherche à décomposer l'organisation des fichiers en plusieurs répertoires.

On a alors plusieurs solutions : on peut demander à PHP de parcourir l'ensemble de nos répertoires pour trouver la classe, à l'aide de différentes implémentations :

  1.    <?php
  2.      
  3.    define('CLASSES_DIR', 'myproject/classes');
  4.      
  5.   function __autoload($classname)
  6.     {
  7.     $classes_dirs = array('core', 'tools', 'model', 'dblayer');
  8.     foreach($classes_dir as $dir)
  9.     {
 10.     $classpath = CLASSES_DIR.'/'.$dir.'/class.'.$classname.'.php';
 11.     if(file_exists($classpath))
 12.     {
 13.     require $classpath;
 14.     return;
 15.     }
 16.     }
 17.     }


On peut aussi faire encore pire : parcourir les répertoires à la recherche du bon fichier et l'inclure ensuite ! Ces méthodes, en plus d'être hasardeuses, sont très couteuses en ressources : on utilise une boucle et on réalise plusieurs opérations sur le système de fichier (qui font partie des opérations les plus lentes d'un programme, à cause notamment du temps d'accès au disque dur).

Une méthode plus élégante serait d'enregistrer dans un tableau la liste de chaque classe associé au fichier qui contient sa définition, on aurait alors, par exemple :

 

  1.     <?php
  2.     $_autoload['MyClass'] = 'core/class.MyClass.php';
  3.     $_autoload['MyModelClass'] = 'model/class.MyModelClass.php';
  4.     $_autoload['EmailEasing'] = 'tools/class.EmailEasing.php';

dans un fichier autoloading.php, et une implémentation de la fonction __autoload comme celle-ci :

   1.     <?php
  2.     define('CLASSES_DIR', 'myproject/classes');
  3.     
  4.     function __autoload($classname)
  5.     {
  6.     static $_autoload = null;
  7.     if(is_null($_autoload))
  8.     require 'autoloading.php';
  9.      
 10.     require CLASSES_DIR.'/'.$_autoload;
 11.     }


On fait un travail plus propre : le fichier contenant la liste des dépendances est inclus une seule fois grâce au fait que la variable soit statique et on évite des recherches inutiles. D'un autre côté, on perd une partie des avantages du chargement dynamique, puisque le développeur devra tout de même maintenir le fameux fichier de dépendances. Quand il n'y en a que quelques unes, ça va, mais c'est quand il y en a beaucoup.

De nombreuses solutions plus ou moins compliquées existent : effectuer une recherche puis mettre en cache, créer un script qui générera le fichier de dépendances qu'on appellera lors de la mise à jour du code, et plus exotique encore.