2009-08-31 28 views
12

Acabo de ver la función autoload() de php. Parece una buena idea, pero no estoy seguro de cómo maneja múltiples directorios. Mi desarrollo actual básicamente tiene una estructura de directorio de biblioteca que agrupa las clases en subdirectorios por operación. Me pregunto si tengo que declarar un include() para cada directorio ... lo cual realmente espero que no tenga que hacer.autoload y directorios múltiples

le puede aconsejar - gracias

Respuesta

1

Desafortunadamente, usted tiene que añadir explícitamente cada directorio. Esto se puede hacer mediante programación en una secuencia de comandos que recorre recursivamente sus directorios, o puede especificar una lista.

Probablemente la manera más eficiente es especificar una lista de directorios y subdirectorios para buscar, y agregarlos a su 'include_path' usando ini_set().

17

Es posible que desee echar un vistazo a PEAR Convention para los nombres de clase, que es realmente genial para la carga automática.

Básicamente, se establece que: jerarquía de clases

La pera es también refleja en el nombre de la clase, cada nivel de la jerarquía separados con un solo subrayado.

Lo que significa que encontrar el archivo para incluir para un nombre de clase HTML_Upload_Error es solo una cuestión de reemplazar '_' por '/'; dándole HTML/Upload/Error.php

Para más explicaciones, y un par de ejemplos, se puede echar un vistazo a los artículos:

Por cierto: esta convención es utilizado por muchos grandes Frameworks/libraries ;-)
Por ejemplo, Zend Framework usa esta convención, ¡y es realmente útil!

+0

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. –

+2

+1 para el enlace de explicación excelente que explica __autoload muy bien: http://blog.straylightrun.net/2009/05/06/autoload-magic/ –

1

Pareces confundido :) O tal vez estoy confundido por tu pregunta.

Depende completamente de usted escribir una función que localice y cargue la clase, a PHP no le importa dónde/cuántos niveles tiene.

Y, mira en SPL autoload too, tiene la misma funcionalidad básica, pero puedes escribir varias funciones de autocarga y luego encadenarlas. Puede ser útil, si desea utilizar algunas bibliotecas externas, que definan sus propios autocargadores que podrían entrar en conflicto con los suyos.

1

Supongo que está hablando de la capacidad de carga automática SPL de PHP, donde escribe su propia función y luego la registra con el SPL.

Cómo lo haces depende de cómo crees tus funciones de inclusión. Es posible declarar múltiples funciones de inclusión y luego registrarlas con PHP: cuántas dependen de usted. La función de autocarga de SPL simplemente le permite crear su propia función y luego decirle a PHP que ejecute esa función cada vez que una clase lo necesite.

Uno de los beneficios de la creación de múltiples es la posibilidad de registrarlos en su orden de uso, el directorio más utilizado primero al menos usado al último. Además, si se cambia o borra un directorio, entonces usted simplemente cambia y/o elimina la función responsable.

Puede escribir una función que irá a través de toda la estructura de la carpeta también (aunque no lo recomendaría para facilitar la administración y desacoplar el código). No existe una forma "técnicamente correcta" de hacerlo :)

10

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; 
    } 

} 
+0

Amazing ClassLoader. – Jerska

1

Como ya se ha mencionado, la carga automática de SPL es funcionalmente una estructura en la que usted tiene que injertar aplicación práctica - convenciones de nomenclatura de directorio transversal y forman parte de estas consideraciones.

Tome un ejemplo práctico en la forma de Zend Loader: en su base, este es un singleton que utiliza una convención de correlación de espacios de nombres para directorios que están registrados con la ruta include de PHP. Ejemplo práctico:

set_include_path(get_include_path(). PATH_SEPARATOR. 'App/'); //Concat the "App" directory onto the existing include paths 
$loader = Zend_Loader::getInstance(); //because the autoloader is a singleton, we get a reference to it without assuming we need to first create it 
$loader->registerNamespace('App_'); //Tell autoloader it can look in the app directory to find classes if it can't find them in the default Zend directory. 

preocupaciones Obviamente específicas de aplicación pueden variar de un proyecto a otro, pero puede ser mejor, tanto como un ejercicio de comprensión y de la reutilización de código, para intentar su mano en la programación de un cargador automático que puede analizar una formato de clase específico (por ejemplo, 'nombre_clase_directorio') en un mapa de directorio, luego cargue y valide la clase.

Cuestiones relacionadas