Too Cool for Internet Explorer

Cómo usar autoload en varios componentes simultáneamente 1

Hora y Fecha: Noviembre 14, 2007 @ 2:36 am Autor: Moisés Maciá
Categorías:
267 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 :(



Automatizando la creación de paquetes Phar con Phing 1

Hora y Fecha: @ 12:39 am Autor: Moisés Maciá
Categorías:
248 views

Os dejo un task para Phing que programé para crear automáticamente paquetes Phar en PHP. Como no hay demasiada documentación sobre cómo extender Phing y crear nuevas tareas, os puede servir de guía para implementar las vuestras porque la verdad es que yo programé esta casi a ciegas.

La tarea: PHPArchiveTask

Y aquí el ejemplo de uso del XML del build.xml correspondiente:

<project name="builder" default="package">
	<!-- custom tasks -->
	<taskdef name="phar" classname="phing.task.PHPArchiveTask" />
	
	<!-- custom properties -->
	<property name="phar.version" value="1" />
	<property name="dist.dir" value="./dist" />
	<property name="src.dir" value="./src" />
	
	
	<target name="package">
		<echo msg="Building package ..." />
		<phar
			version="${phar.version}" 
			bootstrap="lib/phar-bootstrap.php" 
			gzip="true" 
			output="{dist.dir}/packages/myFirstPharPackage${phar.version}.phar" 
			stub="{src.dir}/phar-stub.php">
	
			<fileset dir="{src.dir}">
				<include name="classes/**/*.php" />
			</fileset>
		</phar>
	</target>

</project>

Deberéis colocar la tarea en la ruta phing/task/PHPArchiveTask.php a partir del lugar donde esté el build.xml, tal y como indica el espacio de nombres (de esos espacios de nombres de mentira que hay en PHP…). El resto de opciones creo que están bastante claras.




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