Voici ma première contribution
Je développe en PHP 5.2.6 en POO; actuellement je n'ai que 117 classes mais c'est déjà beaucoup et cela nécessite de l'organisation et surtout de la réorganisation (refactoring).
Je m'étais fait une version simple de la fonction __autoload qui déterminait l'arborescence dans laquelle se trouvait le fichier à inclure selon le nommage de la classe. Mais très vite, j'ai trouvé des limites à ce système car je n'aime pas avoir trop de classes dans un répertoire.
J'ai donc commencé à voir pour un système d'exploration d'un répertoire racine (./inc) afin de localiser le fichier contenant la classe. Mais ce système coûte en ressources et en temps, j'ai alors rajouté une mise en cache simple:
La méthode __class2file() est éventuellement à réécrire pour le lien entre le nom d'une classe et le nom du fichier qui la contient.
Le répertoire initial (./inc) est également modifiable au début de la méthode __classFolder().
Pour l'utiliser, il faut effectuer un traitement au début du script PHP:
et un autre à la fin du script PHP:
Après cet appel,pour des fins statistiques,
ClassAutoLoader::getNbClasses() contient le nombre de classes chargées pour l'exécution du script;
ClassAutoLoader::getDureeChargement() contient la durée de la recherche et du chargement de toutes les classes.
EDIT: Il manque le plus important: les restrictions:
* un nom de classe doit être unique pour toute l'application
* une publication sur un serveur suite à un refactoring doit être précédé par un nettoyage des anciens fichiers; le cache, quant à lui, sait gérer les références mortes.
EDIT2: Encapsulation du code dans une classe
Je développe en PHP 5.2.6 en POO; actuellement je n'ai que 117 classes mais c'est déjà beaucoup et cela nécessite de l'organisation et surtout de la réorganisation (refactoring).
Je m'étais fait une version simple de la fonction __autoload qui déterminait l'arborescence dans laquelle se trouvait le fichier à inclure selon le nommage de la classe. Mais très vite, j'ai trouvé des limites à ce système car je n'aime pas avoir trop de classes dans un répertoire.
J'ai donc commencé à voir pour un système d'exploration d'un répertoire racine (./inc) afin de localiser le fichier contenant la classe. Mais ce système coûte en ressources et en temps, j'ai alors rajouté une mise en cache simple:
<?php
/**
* Gestion du chargement des classes
*
* @author Myrina
* @version 1.0
*/
if (!defined('SITE_ROOTDIR')) {
define('SITE_ROOTDIR',realpath(dirname(__FILE__)));
}
class ClassAutoLoader {
/**
* Nombre de classes chargées
*
* @var Integer
*/
private static $nbClasse;
/**
* Durée totale du chargement des classes
*
* @var Integer
*/
private static $duree;
/**
* Tableau contenant les chemins d'accès aux classes
*
* @var Array
*/
private static $path;
/**
* Transforme le nom de la classe en nom de fichier
*
* @param String $className Nom de la classe
* @return String Nom du fichier à charger
*/
private static function __class2file($className) {
return strtolower($className).'.inc.php';
}
/**
* search for folders and subfolders with classes
*
* @param $className string
* @param $sub string[optional]
* @return string
*/
private static function __classFolder($className, $sub = "/") {
$classDir=SITE_ROOTDIR.'/inc';
$dir = dir($classDir.$sub);
if(file_exists($classDir.$sub.self::__class2file($className)))
return $classDir.$sub;
while(false !== ($folder = $dir->read())) {
if($folder != "." && $folder != "..") {
if(is_dir($classDir.$sub.$folder)) {
$subFolder = self::__classFolder($className, $sub.$folder."/");
if($subFolder)
return $subFolder;
}
}
}
$dir->close();
return false;
}
/**
* Fonction d'autochargement de classe
*
* @param String $class Nom de la classe
*/
public static function __autoload($class) {
list($msec,$sec)=explode(' ',microtime());
$timeDebut=$msec+$sec;
$miniClass=strtolower($class);
if (!is_array(self::$path)) {
self::__initloader();
}
//Recherche dans le cache du répertoire
$ok=false;
if (array_key_exists($miniClass,self::$path)) {
if (file_exists(self::$path[$miniClass].self::__class2file($class))) {
$folder = self::$path[$miniClass];
$ok=true;
}
}
//Si classe pas trouvée en cache, localisation récursive lancée
if (!$ok) {
$folder = self::__classFolder($class);
}
if($folder) {
require_once($folder.self::__class2file($class));
self::$path[$miniClass]=$folder;
} else {
throw new Exception("Class $class not found");
}
list($msec2,$sec2)=explode(' ',microtime());
$timeEnd=$msec2+$sec2;
$duree=$timeEnd-$timeDebut;
self::$duree+=$duree;
self::$nbClasse++;
}
/**
* Fonction d'initalisation des données cachées concernant l'emplacement des classes
*/
public static function __initloader() {
self::$duree=0;
self::$nbClasse=0;
//Chargement du cache d'accès aux classes
if (self::__createcachefolder()) {
if (file_exists(SITE_ROOTDIR.'/cache/classes.cache')) {
self::$path=unserialize(file_get_contents(SITE_ROOTDIR.'/cache/classes.cache'));
} else {
self::$path=array();
}
} else {
self::$path=array();
}
spl_autoload_register(array('ClassAutoLoader','__autoload'));
}
/**
* Fonction de mise en cache des données concernant l'emplacement des classes
*/
public static function __saveloader() {
//Mise en cache
if (self::__createcachefolder()) {
$ser=serialize(self::$path);
$f= fopen(SITE_ROOTDIR.'/cache/classes.cache', "w+");
fputs($f,$ser);
fclose($f);
}
}
/**
* Fonction de suppression du fichier de cache
*/
public static function __cleancacheloader() {
if (self::__createcachefolder()) {
unlink(SITE_ROOTDIR.'/cache/classes.cache');
}
}
/**
* Fonction de création du répertoire de cache si celui-ci n'est pas présent
*
* @return boolean <b>true</b> si le répertoire est OK
*/
private static function __createcachefolder() {
//Si le répertoire n'existe pas
if (!is_dir(SITE_ROOTDIR.'/cache')) {
//Si il peut être créé
if (mkdir(SITE_ROOTDIR.'/cache',0777)) {
return true;
}
} else {
return true;
}
return false;
}
/**
* Renvoie le nombre de classes chargées
*
* @return Integer
*/
public static function getNbClasses() {
return self::$nbClasse;
}
/**
* Renvoie la durée du chargement de toutes les classes chargées
*
* @return Float
*/
public static function getDureeChargement() {
return self::$duree;
}
}
?>
La méthode __class2file() est éventuellement à réécrire pour le lien entre le nom d'une classe et le nom du fichier qui la contient.
Le répertoire initial (./inc) est également modifiable au début de la méthode __classFolder().
Pour l'utiliser, il faut effectuer un traitement au début du script PHP:
//Chargement de la fonction autoload
include_once('class.loader.php');
ClassAutoLoader::__initloader();
//Démarrage de la session
session_start();
et un autre à la fin du script PHP:
ClassAutoLoader::__saveloader();
Après cet appel,pour des fins statistiques,
ClassAutoLoader::getNbClasses() contient le nombre de classes chargées pour l'exécution du script;
ClassAutoLoader::getDureeChargement() contient la durée de la recherche et du chargement de toutes les classes.
EDIT: Il manque le plus important: les restrictions:
* un nom de classe doit être unique pour toute l'application
* une publication sur un serveur suite à un refactoring doit être précédé par un nettoyage des anciens fichiers; le cache, quant à lui, sait gérer les références mortes.
EDIT2: Encapsulation du code dans une classe