Too Cool for Internet Explorer

Reflexión en PHP

Hora y Fecha: Mayo 7, 2005 @ 12:39 am Autor: Moisés Maciá
Categorías:
551 views

La reflexión es una tecnica de programacion avanzada con la que podemos interactuar con los objetos de un programa "preguntandoles" los metodos de los que disponen asi como cambiarlos o añadir nuevos en caliente. Para una definición mas exahustiva y algunos ejemplos podeis leer el apartado al respecto en la wikipedia.

En PHP se implementó una API de reflexión a partir de la versión 5 pero como hay muy muy pocos servidores en producción con la última versión de PHP cargada pues como si no lo hubieran puesto. Lo habitual es encontrar la version 4, pero jugando un poco se puede implementar un sistema de reflexión de andar por casa.

Mi problema era el siguiente: estoy desarrollando un framework ampliable mediante modulos, los modulos estan alojados en un directorio y durante la carga del framework hay que leer dicho directorio, comprobar si los archivos que hay son modulos y extraer una serie de métodos de los mismos. Este es el codigo:


$mod_dir = constant('ABSPATH')."/lib/modules/";

 if ($handle = opendir($mod_dir)) {
  //lee los archivos .php del directorio
  while (false !== ($file = readdir($handle))) {
     if ($file != "." && $file != ".." && preg_match("/.php/",$file)) {
    $mod_name = substr($file,0,strlen($file)-4); //nombre del modulo, en minusculas
    //nombre de la clase: nombre del modulo con la primera letra en mayusculas
    $class_name = strtoupper(substr($mod_name,0,1)).substr($file,1,strlen($file)-5);
    $mod_version = ""; //version del modulo
    $mod_desc = ""; //descripcion del modulo
    $mod_long_desc = ""; //descripcion larga

    //incluimos el codigo y comprobamos si es un modulo valido
    include_once($mod_dir.$file);
    if(is_callable(array($class_name, 'get_version'))) {
     //llamada dinamica al metodo get_version() y get_desc() del modulo
     //reflexion jander klander de PHP4 :)
     $mod_version = call_user_func(array($class_name,"get_version"));
     $mod_desc = call_user_func(array($class_name,"get_desc"));
     $mod_long_desc = call_user_func(array($class_name,"get_long_desc"));
      ...
    }
   }
  }
  closedir($handle);

El truco del almendruco esta en las funciones is_callabe() y call_user_func(), la primera tiene como parametros un array con el nombre de la clase y el nombre del metodo que queremos comprobar, si esta disponible en la clase devuelve TRUE. Nada mas sencillo.

La función is_callable() da mucho juego ya que puede comprobar funciones sueltas o los métodos disponibles de una clase.

Una vez comprobado que el metodo esta disponible es muy tentador invocarlo utilizando el operador de resolución ambito de la forma $class_name::$method_name(); pero no funciona, devuelve parse error, unexpected T_PAAMAYIM_NEKUDOTAYIM (toma ya!). De hecho empleando el operador "flechita" (ahora mismo no me sale el nombre correcto) si se pueden emplear nombres de variables como si fueran métodos de clase.

La forma correcta de llamar a un metodo "desconocido" es con la función call_user_func(), de nuevo con un array con el nombre de la clase y el metodo que queremos, incluso se pueden pasar parametros al metodo en caso de ser necesario.

Todo esto para PHP4 repito, la versión 5 tiene un API especifico para hacer este tipo de guarrerias. Pero para jugar un rato y salir del paso ya vale :)





« Anterior post: Barrapunto flame war How-To | Próximo post: Oh baby que pasó … »

Los comentarios estan cerrados.


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