Pregunta

Me pregunto cuál es la mejor práctica para manejar el problema de tener que "incluir" tantos archivos en mis scripts PHP para garantizar que todas las clases que necesito usar sean accesibles para mi script.

Actualmente solo estoy usando incluir_una vez para incluir las clases a las que accedo directamente.Cada uno de esos include_once las clases a las que acceden.

He investigado el uso de __autoload funciona, pero no parece funcionar bien si planea tener sus archivos de clase organizados en un árbol de directorios.Si hiciera esto, parecería que terminaría recorriendo el árbol de directorios hasta encontrar la clase que estaba buscando. Además, no estoy seguro de cómo esto afecta a las clases con el mismo nombre en diferentes espacios de nombres.

¿Existe una manera más fácil de manejar esto?

¿O simplemente PHP no es adecuado para "empresarial"Aplicaciones de tipo con muchos objetos diferentes, todos ubicados en archivos separados que pueden estar en muchos directorios diferentes.

¿Fue útil?

Solución

Yo mis aplicaciones que normalmente tengo. setup.php archivo que incluye todas las clases principales (es decir,marco y bibliotecas que lo acompañan).Mis clases personalizadas se cargan mediante un cargador automático con la ayuda de un mapa de diseño de directorio.

Cada vez que se agrega una nueva clase, ejecuto un script de creación de línea de comandos que escanea todo el árbol de directorios en busca de clases modelo y luego crea una matriz asociativa con nombres de clases como claves y rutas como valores.Luego, la función __autoload busca el nombre de la clase en esa matriz y obtiene la ruta de inclusión.Aquí está el código:

autoconstrucción.php

define('MAP', 'var/cache/autoload.map');
error_reporting(E_ALL);
require 'setup.php';
print(buildAutoloaderMap() . " classes mapped\n");

function buildAutoloaderMap() {
    $dirs = array('lib', 'view', 'model');
    $cache = array();
    $n = 0;
    foreach ($dirs as $dir) {
        foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir)) as $entry) {
            $fn = $entry->getFilename();
            if (!preg_match('/\.class\.php$/', $fn))
                continue;
            $c = str_replace('.class.php', '', $fn);
            if (!class_exists($c)) {
                $cache[$c] = ($pn = $entry->getPathname());
                ++$n;
            }
        }
    }
    ksort($cache);
    file_put_contents(MAP, serialize($cache));
    return $n;
}

carga automática.php

define('MAP', 'var/cache/autoload.map');

function __autoload($className) {
    static $map;
    $map or ($map = unserialize(file_get_contents(MAP)));
    $fn = array_key_exists($className, $map) ? $map[$className] : null;
    if ($fn and file_exists($fn)) {
        include $fn;
        unset($map[$className]);
    }
}

Tenga en cuenta que la convención de nomenclatura de archivos debe ser [nombre_clase].class.php.Modifique los directorios en los que se buscarán las clases. autobuild.php.También puede ejecutar el constructor automático desde la función de carga automática cuando no se encuentra la clase, pero eso puede hacer que su programa entre en un bucle infinito.

Los arreglos serializados son increíblemente rápidos.

@JasonMichael:PHP 4 está muerto.Superalo.

Otros consejos

Puede definir múltiples funciones de carga automática con spl_autoload_register:

spl_autoload_register('load_controllers');
spl_autoload_register('load_models');

function load_models($class){
    if( !file_exists("models/$class.php") )
        return false;

    include "models/$class.php";
    return true;
}
function load_controllers($class){
    if( !file_exists("controllers/$class.php") )
        return false;

    include "controllers/$class.php";
    return true;
}

También puede determinar mediante programación la ubicación del archivo de clase utilizando convenciones de nomenclatura estructuradas que se asignan a directorios físicos.Así lo hace Zend Marco Zend.Entonces cuando llamas Zend_Loader::loadClass("Zend_Db_Table"); explota el nombre de la clase en una matriz de directorios dividiéndolos en guiones bajos, y luego la clase Zend_Loader va a cargar el archivo requerido.

Como todos los módulos de Zend, esperaría que puedas usar solo el cargador con tus propias clases, pero yo solo lo he usado como parte de un sitio que usa MVC de Zend.

Pero ha habido preocupaciones sobre el rendimiento bajo carga cuando se utiliza cualquier tipo de carga de clases dinámica, por ejemplo ver esta publicación de blog comparando Zend_Loader con la carga dura de archivos de clase.

Además de la penalización en el rendimiento de tener que buscar la ruta de inclusión de PHP, anula el almacenamiento en caché del código de operación.De un comentario en esa publicación:

Cuando se utiliza CUALQUIER cargador de clases dinámico, APC no puede almacenar en caché esos archivos por completo porque no está seguro de qué archivos se cargarán en una sola solicitud.Al cargar los archivos con fuerza, APC puede almacenarlos en caché en su totalidad.

__autoload funciona bien si tiene una convención de nomenclatura coherente para sus clases que le indique a la función dónde se encuentran dentro del árbol de directorios.MVC se presta particularmente bien para este tipo de cosas porque puedes dividir fácilmente las clases en modelos, vistas y controladores.

Alternativamente, mantenga una matriz asociativa de nombres para ubicar los archivos de su clase y deje que __autoload consultar esta matriz.

De las sugerencias hasta ahora, soy partidario de la de Kevin, pero no es necesario que sea absoluta.Veo un par de opciones diferentes para usar con __autoload.

  1. Coloque todos los archivos de clase en un solo directorio.Nombra el archivo después de la clase, es decir, classes/User.php o classes/User.class.php.
  2. La idea de Kevin de poner modelos en un directorio, controladores en otro, etc.Funciona bien si todas tus clases encajan bien en el marco MVC, pero a veces las cosas se complican.
  3. Incluya el directorio en el nombre de la clase.Por ejemplo, una clase llamada Model_User en realidad estaría ubicada en classes/Model/User.php.Su función __autoload sabría traducir un guión bajo en un separador de directorio para encontrar el archivo.
  4. Simplemente analice toda la estructura del directorio una vez.Ya sea en la función __autoload, o incluso simplemente en el mismo archivo PHP donde está definido, recorra el contenido del classes directorio y caché qué archivos están dónde.Entonces, si intentas cargar el User clase, no importa si es en classes/User.php o classes/Models/User.php o classes/Utility/User.php.Una vez que encuentre User.php en algún lugar del classes directorio, sabrá qué archivo incluir cuando el User La clase necesita cargarse automáticamente.

@Kevin:

Solo estaba tratando de señalar que spl_autoload_register es una mejor alternativa a __autoload ya que puedes definir múltiples cargadores y no entrarán en conflicto entre sí.Útil si también tiene que incluir bibliotecas que definan una función __autoload.

¿Está seguro?El documentación dice diferente:

Si su código tiene una función __autoload existente, entonces esta función debe registrarse explícitamente en la pila __autoload.Esto se debe a que spl_autoload_register() reemplazará efectivamente el caché del motor para la función __autoload por spl_autoload() o spl_autoload_call().

=> tienes que registrar explícitamente cualquier biblioteca __autoload también.Pero aparte de eso, tienes razón: esta función es la mejor alternativa.

__autoload funcionará, pero sólo en PHP 5.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top