Aquí hay una clase que escribí hace un tiempo con un propósito similar. Esa vez todavía estaba en la fase de aprendizaje, por lo que podría haber ideas estúpidas involucradas; funcionó sin embargo.
La idea básica es que escanea el directorio de origen una vez y crea una clase de asignación de matriz en sus archivos de origen. La clase está registrada como autocargador y, cuando se invoca, incluye el archivo requerido. Si no se encuentra, intenta reconstruir la matriz sobre la marcha.
/* register ClassLoader as class loader */
spl_autoload_register(array(ClassLoader::getInstance(), 'loadClass'));
class ClassLoader {
private static $SAVE_FILE = 'ClassLoader.save.php';
/* singleton */
private static $instance;
/* stores a className -> filePath map */
private $classList;
/* tells whether working from saved file */
private $refreshed;
public static function getInstance() {
if (!isset(self::$instance)) {
self::$instance = new ClassLoader();
}
return self::$instance;
}
private function __construct() {
$this->initClassList();
}
public function loadClass($className) {
if (!array_key_exists($className, $this->classList) && !$this->refreshed) {
$this->refreshClassList();
}
require_once($this->classList[$className]);
}
private function initClassList() {
if (file_exists(INCLUDES_DIR . self::$SAVE_FILE)) {
require_once(INCLUDES_DIR . self::$SAVE_FILE);
$this->refreshed = FALSE;
} else {
$this->refreshClassList();
}
}
private function refreshClassList() {
$this->classList = $this->scanDirectory(INCLUDES_DIR);
$this->refreshed = TRUE;
$this->saveClassList();
}
private function saveClassList() {
$handle = fopen(INCLUDES_DIR . self::$SAVE_FILE, 'w');
fwrite($handle, "<?php\r\n");
foreach($this->classList as $class => $path) {
$line = '$this->classList' . "['" . $class . "'] = '" . $path . "';\r\n";
fwrite($handle, $line);
}
fwrite($handle, '?>');
fclose($handle);
}
private function scanDirectory ($directory) {
// strip closing '/'
if (substr($directory, -1) == '/') {
$directory = substr($directory, 0, -1);
}
if (!file_exists($directory) || !is_dir($directory) || !is_readable($directory)) {
return array();
}
$dirH = opendir($directory);
$scanRes = array();
while(($file = readdir($dirH)) !== FALSE) {
// skip pointers
if (strcmp($file , '.') == 0 || strcmp($file , '..') == 0) {
continue;
}
$path = $directory . '/' . $file;
if (!is_readable($path)) {
continue;
}
// recursion
if (is_dir($path)) {
$scanRes = array_merge($scanRes, $this->scanDirectory($path));
} elseif (is_file($path)) {
$className = explode('.', $file);
if (strcmp($className[1], 'class') == 0 && strcmp($className[2], 'php') == 0) {
$scanRes[$className[0]] = $path;
}
}
}
return $scanRes;
}
}
He encontrado que este método funciona muy bien. Otro método que he usado es usar un paquete estático para el mapa de carpetas, que apunta a los directorios raíz bajo los cuales se aplica el método anterior. –
+1 para el enlace de explicación excelente que explica __autoload muy bien: http://blog.straylightrun.net/2009/05/06/autoload-magic/ –