2009-04-27 5 views
36

Al igual que la mayoría de los desarrolladores web en estos días, estoy disfrutando plenamente de los beneficios de la sólida arquitectura MVC para aplicaciones y sitios web. Al hacer MVC con PHP, la carga automática obviamente es extremadamente útil.Estrategias eficientes de carga automática y asignación de nombres de PHP

Me he convertido en un fan de spl_autoload_register simplemente definiendo una sola función __autoload(), ya que es obviamente más flexible si está incorporando diferentes módulos base que cada uno usa su propia carga automática. Sin embargo, nunca me he sentido bien con las funciones de carga que escribo. Implican una gran cantidad de comprobación de cadenas y escaneo de directorios para buscar posibles clases para cargar.

Por ejemplo, digamos que tengo una aplicación que tiene una ruta de la base definida como PATH_APP, y una estructura sencilla con directorios llamados models, views y controllers. A menudo utilizo una estructura de nombres por la cual los archivos se llaman IndexView.php y IndexController.php dentro del directorio apropiado, y los modelos generalmente no tienen un esquema particular por defecto. Puede que tenga una función de cargador para esta estructura como esta que consigue registrado en spl_autoload_register:

public function MVCLoader($class) 
{ 
    if (file_exists(PATH_APP.'/models/'.$class.'.php')) { 
     require_once(PATH_APP.'/models/'.$class.'.php'); 
     return true; 
    } 
    else if (strpos($class,'View') !== false) { 
     if (file_exists(PATH_APP.'/views/'.$class.'.php')) { 
      require_once(PATH_APP.'/views/'.$class.'.php'); 
      return true; 
     } 
    } 
    else if (strpos($class,'Controller') !== false) { 
     if (file_exists(PATH_APP.'/controllers/'.$class.'.php')) { 
      require_once(PATH_APP.'/controllers/'.$class.'.php'); 
      return true; 
     } 
    } 
    return false; 
} 

Si no se encuentra después de eso, podría tener otra función para escanear subdirectorios en el directorio de modelos. Sin embargo, todo el análisis if/else -ing, la verificación de cadenas y el escaneo de directorios me parece ineficiente, y me gustaría mejorarlo.

Tengo mucha curiosidad acerca de qué nombre de archivo y estrategias de carga automática pueden emplear otros desarrolladores. Estoy buscando específicamente buenas técnicas para emplear para la carga automática eficiente, y no alternativas a la carga automática.

Respuesta

28

Esto es lo que he estado usando en todos mis proyectos (levantado directamente de la fuente de la última):

public static function loadClass($class) 
{ 
    $files = array(
     $class . '.php', 
     str_replace('_', '/', $class) . '.php', 
    ); 
    foreach (explode(PATH_SEPARATOR, ini_get('include_path')) as $base_path) 
    { 
     foreach ($files as $file) 
     { 
      $path = "$base_path/$file"; 
      if (file_exists($path) && is_readable($path)) 
      { 
       include_once $path; 
       return; 
      } 
     } 
    } 
} 

Si busco SomeClass_SeperatedWith_Underscores buscará SomeClass_SeperatedWith_Underscores.php seguido por SomeClass /SeperatedWith/Underscores.php enraizado en cada directorio en la ruta de inclusión actual.

EDIT: Sólo quería decir que uso esto para la eficiencia en el desarrollo, y no necesariamente el tiempo de procesamiento. Si tiene PEAR en su camino, puede usar las clases y no tiene que incluirlas cuando las necesite.

Tiendo a mantener mis clases en una jerarquía de directorios, con subrayados que rompen espacios de nombres ... Este código me permite mantener la estructura de archivos ordenada y agradable si lo deseo, o inyectar un archivo de clase rápido sin directorios anidados si Quiero (por la adición de una sola clase o dos para una biblioteca que es acusado, pero no forma parte del proyecto Actualmente estoy trabajando.)

+3

proxeneta +1 por frialdad – Louis

+0

Definitivamente me gusta el enfoque de subrayado. Hace la traducción de clase a archivo mucho más eficiente. – zombat

+3

Ajustar 'array_unique()' alrededor de su matriz '$ files'. Si no hay guiones bajos en el nombre de la clase, está probando cada archivo dos veces. – mpen

13

aterricé en esta solución:

creé una sola secuencia de comandos que atraviesa mi carpeta de biblioteca de clase (que contiene subcarpetas para módulos/sistemas separados) y analiza el contenido del archivo buscando definiciones de clase. Si encuentra una definición de clase en un archivo PHP (patrón de expresión muy simple), se crea un enlace simbólico:

class_name.php -> actual/source/file.php 

Esto me permite usar una única función, carga automática simple que necesita sólo el nombre de la clase y el camino a la carpeta principal de enlace simbólico, y no tiene que hacer ninguna manipulación de camino/cadena.

La mejor parte es que puedo reorganizar mi código fuente por completo o agregar un nuevo subsistema y simplemente ejecutar el script de generación de enlaces para tener todo cargado automáticamente.

+0

Esa es probablemente la solución más creativa que he encontrado. Buen material. Solo por curiosidad, ¿cuán multiplataforma sería ese enfoque? – zombat

+4

Desde que comencé a trabajar con Linux, uno de mis mayores problemas con Windows ha sido la falta de enlaces simbólicos. Hasta donde yo sé, esta solución solo funciona con unixes. – grossvogel

+5

FYI, puede usar 'mklink' para crear enlaces simbólicos en Windows: http://www.howtogeek.com/howto/windows-vista/using-symlinks-in-windows-vista/ –

7

Si desea eficiencia, no debe utilizar la función de autocarga. La función de autocarga es para ser flojo. Debería proporcionar una ruta de acceso explícita a sus archivos de inclusión cuando los incluya. Si la función de autocarga puede encontrar estos archivos, puede codificar para encontrarlos de manera explícita. Cuando trabajas en la parte de vista del código y estás a punto de cargar una nueva clase de vista, al dejar que la función de autocarga lo maneje, primero asume que tu clase es una clase de modelo. Eso es ineficiente. En cambio el código debe ser simplemente:

include_once $this->views_path . $class . '.php'; 

Si necesita varias rutas de acceso "Ver", crear una función que carga vistas:

public function load_view($class) { 
    // perhaps there's a mapping here instead.... 
    foreach ($this->views_paths as $path) { 
     $filename = $path . $class . '.php'; 
     if (file_exists($filename)) { 
      include_once $filename; 
     } 
    } 
    throw .... 
} 

En cualquier caso, en el punto en el include ocurre, se tener la mayor/más precisa información sobre la clase que desea cargar. Usar esa información para cargar la clase por completo es la única estrategia eficiente de carga de clases. Sí, puedes terminar con más variables de clase o (cielo no lo permita) algunas variables globales. Pero esa es una mejor solución que simplemente ser flojo y escanear partes del sistema de archivos para su clase.

+10

Si bien tienes razón acerca de que la carga directa es la más eficiente en general, hace que el código sea más difícil de mantener. ¿Qué sucede si cambia el nombre de una clase o un archivo? O digamos que tengo segmentos de vista dinámica que el controlador puede cargar y, a medida que avanza el proyecto, se crean cada vez más clases de vista. Cada vez que creo una clase de vista, no quiero tener que volver atrás y modificar un controlador para incluirlo manualmente donde sea que se use. Acepto que la carga automática es menos eficiente que la carga directa, pero estoy buscando la carga automática más eficiente. – zombat

+1

Estoy de acuerdo con zombat. La pereza puede ser algo bueno; también se conoce como trabajo eficiente. En cuanto a rendimiento, el hardware es barato. – rick

+2

Si tiene que cambiar el nombre de una clase después de que llega a la producción, no está pasando suficiente tiempo diseñando antes de escribir el código. Si la eficiencia es importante, pasar más tiempo por adelantado ahorra infinitamente más tiempo en mantenimiento que las funciones perezosas de "no se preocupe por nada en absoluto" como la carga automática. – jmucchiello

Cuestiones relacionadas