Too Cool for Internet Explorer

Cómo usar autoload en varios componentes simultáneamente

Hora y Fecha: Noviembre 14, 2007 @ 2:36 am Autor: Moisés Maciá
Categorías:
268 views

Autoload es uno de los llamados métodos mágicos de PHP que se dispara “mágicamente” cuando, al instanciar una clase, el interprete no es capaz de localizarla porque no se ha hecho el include/require del archivo correspondiente. Con autoload podemos sobrecargar esta funcionalidad y especificarle a PHP donde debe buscar sin tener que indicar explicita mente todos los archivos de clases de nuestro proyecto mediante include/require.

El problema viene cuando nuestro proyecto utiliza su propio autoload y un componente de un tercero utiliza otro autoload completamente diferente: sólo puede haber un punto para interceptar la llamada “autoload” e inevitablemente colisionan.

Afortunadamente la SPL proporciona un mecanismo para apilar métodos autoload, tantos como sean necesarios, y evitar las colisiones. Veamos un ejemplo:

  1. class Component1
  2. {
  3.     public function __construct( $foo )
  4.     {
  5.         echo $foo;
  6.     }
  7. }
  8.  
  9. function __autoload ( $class_name )
  10. {
  11.     if ( !exist_class($class_name) )
  12.     {
  13.         $f = dirname(__FILE__) . ‘/component1/lib/’ . $class_name . ‘.php’;
  14.         if ( file_exists($f) )
  15.         {
  16.             require ($f);
  17.         }
  18.         else
  19.         {
  20.             throw new Exception(‘Unnable to find class ‘ . $class_name . ‘!’, 0);
  21.         }
  22.     }
  23. }
  1. class Component2
  2. {
  3.     public function __construct( $bar )
  4.     {
  5.         echo $bar;
  6.     }
  7. }
  8.  
  9. function __autoload ( $class_name )
  10. {
  11.     if ( !exist_class($class_name) )
  12.     {
  13.         $f = dirname(__FILE__) . ‘/component2/lib/’ . $class_name . ‘.php’;
  14.         if ( file_exists($f) )
  15.         {
  16.             require ($f);
  17.         }
  18.         else
  19.         {
  20.             throw new Exception(‘Unnable to find class ‘ . $class_name . ‘!’, 0);
  21.         }
  22.     }
  23. }

Las clases Component1 y Component2 tienen dos funciones __autoload() diferentes.

  1. include ‘./Component1.php’;
  2. include ‘./Component2.php’;
  3.  
  4. $c1 = new Component1_Lib(); // error!!

Los dos callbacks autoload colisionan.

Utizando SPL podemos detectar si ya hay un callback autoload definido para sobreescribirlo, o apilar el nuestro. Además la función autoload puede meterse como metodo de una clase y mejorar un poco el aspecto del codigo:

  1.  
  2. class Component1
  3. {
  4.     public function __construct( $foo )
  5.     {
  6.         echo $foo;
  7.     }
  8.    
  9.     public function autoload( $class_name )
  10.     {
  11.         if ( !exist_class($class_name) )
  12.         {
  13.             $f = dirname(__FILE__) . ‘/component1/lib/’ . $class_name . ‘.php’;
  14.             if ( file_exists($f) )
  15.             {
  16.                 require ($f);
  17.             }
  18.             else
  19.             {
  20.                 throw new Exception(‘Unnable to find class ‘ . $class_name . ‘!’, 0);
  21.             }
  22.         }
  23.     }
  24. }
  25.  
  26.  
  27. $callbacks = spl_autoload_functions();
  28. // no autoload callbacks in stack
  29. if ( $callbacks === false )
  30. {
  31.     spl_autoload_register( array(‘Component1′, ‘autoload’) );
  32. }
  33. else
  34. {
  35.     // unregister existing callbacks
  36.     foreach ( $callbacks as $callback )
  37.     {
  38.         spl_autoload_unregister($callback);
  39.     }
  40.  
  41.     // register custom callback
  42.     spl_autoload_register( array(‘Component1′, ‘autoload’) );
  43.  
  44.     // re-register old ones
  45.     foreach ( $callbacks as $callback )
  46.     {
  47.         spl_autoload_register($callback);
  48.     }
  49. }
  50.  

Cuidado porque la función autoload no es demasiado liviana y un uso abusivo puede provocar una bajada de rendimiento en el programa, pero de momento y hasta la versión 5.3, sin espacios de nombres en PHP no podemos hacer gran cosa :(





« Anterior post: Automatizando la creación de paquetes Phar con Phing | Próximo post: “Time Machine” para cualquier UNIX »

Un Comentario para “Cómo usar autoload en varios componentes simultáneamente”

Enlaces de la semana 3 — Viciao2k3
9 de Agosto de 2008 a las 9:32 pm    

[...] Cómo usar autoload en varios componentes simultáneamente [...]


Bad Behavior has blocked 287 access attempts in the last 7 days.