Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Otros entornos y lenguajes > PHP
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 08-03-2008
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Auto carga de clases en PHP 5

Hola,

Creo haber encontrado una forma más o menos curiosa y elegante (y no tengo abuela) de implementar la función mágica "__autoload()" de PHP 5. Quisiera compartirla con vosotros, y, por supuesto, recibir alguna idea, crítica o sugerencia. Explicaré un poco por encima lo que significa la función "__autoload()" en PHP 5. Lamentaré aburrir a quien ya sepa esto.

Anteriormente a la existencia de esta función, cuando uno quería utilizar una clase en PHP, tenía antes que requerir su "script", es decir, el archivo donde se implementara la clase. Esto, que, con dos o tres clases, puede no ser problema alguno, cuando las clases empiezan a ser algunas más, obliga a conformar "ristras" de "requires", cuyos "elementos" además tienen que guardar cierto orden.

Es decir, pongamos por caso:

Código PHP:
require('bd.class.php');
require(
'input.class.php');
require(
'request.class.php');
require(
'response.class.php');
require(
'frontend.class.php');


$frontEnd = new FrontEnd(); 
Para utilizar la clase "FrontEnd()" y, puesto que suponemos necesarias las demás, hemos tenido que ir requiriendo una a una cada clase, y esta operación había de repetirse en cada uno de los "scripts" en que fuera menester, lo que significaba aumentar la cantidad de código requerido y los posibles problemas derivados del mismo.

La función "__autoload()" viene a solucionar esta problemática. Se considera una función "mágica", porque, es el propio PHP el encargado de ejecutarla, si es que está implementada, lógicamente. En este caso, PHP ejecutará la función "__autoload()" cada vez que se requiera una clase, es decir:

Código PHP:

// Aquí se ejecutará la función "__autoload()"

$frontEnd = new FrontEnd(); 
En realidad no tengo claro que se ejecute donde digo, pero, la idea es que PHP ejecutará la función cuando vea que se precisa la clase "FrontEnd", en este caso. Y pasará a dicha función, como parámetro, el nombre de la clase que se requiere. A partir de ahí es tarea de uno requerir la clase "de verdad", para que pueda ser utilizada.

Ahora bien, aunque la función "__autoload()" es nuestra amiga y quiere ayudarnos, ya he dicho que su implementación depende uno, y que esta se puede llevar a cabo de distintas formas, atendiendo a las necesidades de cada aplicación, evidentemente. Yo quiero hablar ahora sobre la implementación de la función "__autoload()" en el gestor de bitácoras Gesbit, que algunos ya conocéis.

En Gesbit sigo la siguiente regla: todas las clases propias se encuentran en un directorio para tal efecto, y, todas las clases de librerías (o bibliotecas) de terceros, se encuentran en subdirectorios del directorio de clases "principal" mencionado. Lo de menos es porqué hago esto, aunque, claro está, la idea subyacente (siempre quise decir esto) se ve como positiva.

Lo que nos importa ahora, conociendo lo dicho, es cómo implementar la función "__autoload()" de PHP teniendo esto en cuenta. El asunto pasa por buscar la clase que PHP está requiriendo, pasada como parámetro a la función, intentar encontrar la clase que se necesita, y, de hacerlo, requerirla sin más, para que PHP pueda seguir procesando nuestro "script".

Así pues, uno se plantea algo muy similar a lo siguiente:

Código PHP:
define('GB_AUTOLOAD_CLASS_EXT''.class.php');
define('GB_AUTOLOAD_CONST_EXT''.const.php');
 
function 
__autoload($className){
  
$className strtolower($className);
  
$classFile $className.GB_AUTOLOAD_CLASS_EXT;
  
$constFile $className.GB_AUTOLOAD_CONST_EXT;
  if(
file_exists(GB_CLASSES_DIR.$classFile)){    
    require(
GB_CLASSES_DIR.$classFile);
    if(
file_exists(GB_CLASSES_DIR.$constFile)){
      require(
GB_CLASSES_DIR.$constFile);
    }
  }elseif(
file_exists(GB_KSES_DIR.$classFile)){
    require(
GB_KSES_DIR.$classFile);
  }elseif(
file_exists(GB_PHPASS_DIR.$classFile)){
    require(
GB_PHPASS_DIR.$classFile);
  }elseif(
file_exists(GB_SNOOPY_DIR.$classFile)){
    require(
GB_SNOOPY_DIR.$classFile);        
  }elseif(
file_exists(GB_PHPGETTEXT_DIR.$classFile)){
    require(
GB_PHPGETTEXT_DIR.$classFile);  
  }elseif(
file_exists(GB_IXMLRPC_DIR.$classFile)){
    require(
GB_IXMLRPC_DIR.$classFile);
  }

He quitado los comentarios al código, pero, la idea se entiende bien, creo yo: se trata de conformar el nombre del "script" de la clase, que, en este caso, tendrá siempre una determinada extensión. Como particularidad, hago notar que se busca también un archivo que contendrá "constantes" para usarse en la clase a requerir, y, si este existe, se incluye también.

Pero, fíjate lo que ocurre con las clases de terceros. Al estar cada una de ellas en directorios diferentes, en el código anterior se trataba de encontrar el "script" de la clase en cuestión en todos los directorios posibles. Si se encontraba en alguno de ellos, ya no se miraba más allá, se requería la clase, y aquí paz y después gloria. Pero tiene un inconveniente, al menos.

Tal y como lo ves, no cambiaba el código por los "require" de PHP 4, es decir, creo que la idea subyacente (otra vez) no está mal, y que la implementación de la función "__autoload()" puede servir, en un primer momento. De hecho ha servido para Gesbit durante los últimos meses. Ahora bien, ¿qué pasa cuando se han de añadir más clases de terceros?

Efectivamente, que la función "__autoload()" crecerá y crecerá, conforme se vayan añadiendo más clases de terceros, cada una de ellas en sus propios directorios. Pues bien. Hoy me volví a plantear el problema, y, aunque no di en principio con una solución, creo que al cabo sí que he conseguido algo que, además de que mantiene el rendimiento del "script" o incluso lo mejora, creo que "escala" mejor.

El código en cuestión, es este:

Código PHP:
$libDirs = array(
  
GB_KSES_DIR,
  
GB_PHPASS_DIR,
  
GB_SNOOPY_DIR,
  
GB_IXMLRPC_DIR,
  
GB_CLASSES_DIR,
  
GB_PHPGETTEXT_DIR
);
 
function 
__autoload($className){
  
$className strtolower($className);
  
$classFile $className.'.class.php';
  
$constFile $className.'.const.php';
  foreach(
$GLOBALS['libDirs'] as $dir){
    if(
file_exists($dir.$classFile)){    
      require(
$dir.$classFile);
      if(
file_exists($dir.$constFile)){
        require(
$dir.$constFile);
      }
      break;
    }
  }

Es decir, primero preparamos en un "array" todos los directorios de todas las librerías (o bibliotecas) de terceros, este "array" será el único al que haya que añadir elementos, según se necesiten más clases. Y, por su parte, la función "__autoload()", hace exactamente lo mismo de antes (sigue requiriendo el archivo de "constantes", que, en realidad, es propio de Gesbit, quiero decir, tú podrías muy bien no necesitarlo) y hace lo que se espera de ella exactamente igual o mejor, como he dicho.

En fin. Una vez que he terminado de escribir esto me parece un poco tonto publicarlo aquí. Puede que incluso lo haga en mi bitácora también. Digo que me parece un poco tonto, porque, visto en perspectiva, la cosa parece bastante clara. Es como si vieras este último código y dijeras, ¡pues claro! ¿Es que no lo hacías así? Pero, evidentemente, no lo hacía así. He mostrado (en el primer bloque de código) cómo lo hacía.

Y no sólo eso, sino que podría enlazar a una entrada en la bitácora de Gesbit donde, precisamente, llegué a plantearme una solución mucho más drástica y de la que me hubiera arrepentido: meter todas las clases en un mismo directorio... con el consiguiente lío, puesto que algunas librerías (o bibliotecas) de terceros incorporan más de una clase, y otras pueden incorporar también otros archivos, etc.

En definitiva, que, aunque tal vez ahora me parece evidente, quizás alguien pueda encontrar de utilidad este texto. Yo así lo espero.
__________________
David Esperalta
www.decsoftutils.com

Última edición por dec fecha: 08-03-2008 a las 05:06:15.
Responder Con Cita
  #2  
Antiguo 08-03-2008
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

Voy a dar un empujoncito a este hilo, pero, porque he "descubierto" una forma de mejorar un poco lo dicho en el anterior mensaje. Tengo la manía de escribir código "en escalón", y digo manía, porque es una tontería, pero, chico, no puedo evitarlo. Y el caso es que tiendo a escribir código como el anterior:

Código PHP:
$libDirs = array(
  
GB_KSES_DIR,
  
GB_PHPASS_DIR,
  
GB_SNOOPY_DIR,
  
GB_IXMLRPC_DIR,
  
GB_CLASSES_DIR,
  
GB_PHPGETTEXT_DIR
); 
¿Qué quiero decir con que escribo código "en escalón"? Pues ahora lo verás. El "array" anterior, la función de ese "array", puede mejorarse un poco. ¿Cómo? Situando primero los directorios que más tienden a utilizarse. Puede darse el caso de que uno de los directorios contenga, literalmente, más clases que los otros, y que además estas tiendan a usarse más.

En el caso del programa de que hablé antes (Gesbit) es así. El directorio de clases "propias" se utiliza más, es decir, estas clases se utilizan más y además son más numerosas. Por ejemplo, las clases correspondientes al servidor XML-RPC sólo se utilizan con "clientes" que hacen este tipo de peticiones, que no son la mayoría, en este caso. Es por esto que el "array" anterior debe quedar más o menos así:

Código PHP:
$libDirs = array(
  
GB_CLASSES_DIR,
  
GB_PHPGETTEXT_DIR,
  
GB_KSES_DIR,
  
GB_PHPASS_DIR,
  
GB_SNOOPY_DIR,
  
GB_IXMLRPC_DIR
); 
¡Aunque el código ya no esté "escalonado"! Normalmente esto no importa (es una manía mía) pero, en este caso sí que es importante, porque estaremos ahorrando unas cuentas "iteraciones" en el bucle "foreach" que usamos arriba. Así que nada, ahí queda, para quien pueda aprovecharlo alguna vez, llegado el caso.
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Los ayudantes de clases (o clases ayudantes), ¿ya se gestaban en Delphi 7? Al González OOP 5 12-12-2007 09:03:52
EAN 128 Auto Switch ?? ofillia Varios 2 02-02-2007 19:07:03
Auto completar un edit... Perio SQL 5 19-05-2005 03:09:43
auto incremento valentino MySQL 1 14-02-2005 12:59:33
Auto borrado brandolin Varios 6 27-09-2003 21:18:37


La franja horaria es GMT +2. Ahora son las 18:12:15.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi