A la hora de usar frameworks los programadores esperan cierta magia, que las cosas funcionen sin tener que preocuparse por ciertos detalles nimios, y eso en gran parte se consigue gracias a los métodos de introspección (o reflexión, aunque prefiero el primer término), que en este caso nos son brindados por PHP.
Se podría decir que en PHP hay dos caminos para usar la introspección, el uso de ciertas funciones que aparecieron a partir de la versión 4 de PHP (siguiendo el paradigma de la programación estructurada) , o bien el uso de ciertas clases (y sus respectivos objetos, obviamente) que hicieron su aparición estelar con PHP 5.
Por diversos motivos, en el framework que estoy desarrollando he escogido el segundo camino (en realidad un mix, pero predomina la segunda opción), pero aquí comentaré los dos.
Introspección al estilo de PHP 4
Los primeros métodos que deberíamos conocer son los que nos permiten saber qué clases hay declaradas, o si una determinada clase está cargada ya en el contexto en el que nos encontramos, tenemos estos métodos:
- get_declared_classes () : retorna una lista que contiene los nombres de todas las clases declaradas.
- class_exists ($nombre_clase): retorna verdadero o falso en función de si la clase pasada como parametro ha sido declarada o no. Como parámetro podemos pasar una cadena, o la propia clase si ya la conocemos. Ejemplo:
1
2
3
4
| class Prueba {
}
class_exists ('Prueba'); // Retorna verdadero
class_exists (Prueba); // También retorna verdadero |
Una vez sabemos qué clases hay declaradas, también podríamos querer cómo son éstas por dentro, tenemos los siguientes métodos (creo que esta lista no es exhaustiva):
- get_class_methods ($nombre_clase) : Nos devuelve una lista con los nombres de todos los métodos de la clase
- get_class_vars ($nombre_clase) : Nos devuelve una lista asociativa con los nombres de las propiedades como claves, y los respectivos valores de las propiedades como elementos de la lista.
- property_exists ($nombre_clase, $nombre_propiedad) : Nos indica si la clase tiene la propiedad que buscamos
- get_parent_class ($nombre_clase) : Nos devuelve el nombre de la clase padre (si no hay clase padre, entonces devuelve una cadena vacía). También podemos usar objetos en este caso, no solo clases.
- is_subclass_of ($nombre_clase, $nombre_clase_padre) : Nos indica si la clase hereda de la clase padre, también podemos usar objetos en este caso, no solo clases.
Podemos hacer prácticamente lo mismo, pero con objetos:
- get_object_vars ($objeto) : Se parece mucho a get_class_vars , pero se diferencia en que los valores de las propiedades de los objetos pueden variar en tiempo de ejecución, y además se pueden añadir propiedades también en tiempo de ejecución.
- method_exists ($objeto, $nombre_metodo) : Nos indica si el objeto tiene o no un método concreto
Y aquí nos quedamos, más o menos eso es todo. Antes había ciertas funciones que completaban la parrilla y eran bastante útiles, que servían, básicamente, para hacer uso de callbacks o ejecutar métodos de forma "dinámica", pero fueron marcadas como obsoletas a partir de la versión 4.1 de PHP, por lo que no las comentaré. El hecho de que "falten" ciertas funciones nos podría obligar a agudizar el ingenio.. o a abusar de funciones como eval , pero por suerte, en PHP 5 se introdujo una nueva forma de trabajar.
Introspección al estilo PHP 5 (clase Reflection)
En PHP 5 se introdujeron diversas mejoras, entre otras el tratamiento de errores se ha orientado más hacia el manejo de excepciones con bloques try-catch , y se han creado más clases que permiten trabajar de una forma mucho más orientada al paradigma de Orientación a Objetos, aumentando en cierta medida la cohesión del código resultante.
Una de las clases que fueron introducidas en esta versión fue la clase Reflection (y algunas otras que derivan de ésta). Todas ellas, cuando se produce algún error, lo que hacen es lanzar una excepción, simplificando la gestión y evitando que tengamos que interpretar el significado de los valores de retorno. Estas son las clases de las que hablaremos (un poco por encima):
Para hacer introspección o reflexión lo que debemos es construir un objeto a partir de una de estas clases, usando como parámetro en el constructor aquello que queramos "ver por dentro". Por ejemplo:
1
| $metainformacion_clase = new ReflectionClass ("nombre_de_la_clase"); |
a partir de aquí contamos con un montón de métodos (muchos más que los que había disponibles en PHP 4) que nos servirán para conocer todo cuanto queramos sobre la susodicha clase. Podéis ver los métodos disponibles en los enlaces que he hecho para cada una de ellas. Es interesante comentar que, algunos métodos devuelven objetos que a su vez también sirven para aplicar introspección, como getMethod ($name) o getProperty ($name) , que devuelven sendos ReflectionMethod i ReflectionProperty.
Uno de los métodos más interesantes de ReflectionMethod es el método invoke ($object, $params) , al cual le podemos pasar un objeto para el que queremos que se ejecute el método reflejado con los parámetros indicados. Esto sería "equivalente" a hacer la llamada (atentos, el ==== no es código, lo uso para indicar una cierta equivalencia):
1
| $metainformacion_metodo->invoke($object, $params); ==== $object->metodo_reflejado($params); |
Con ésto no es que se pueda zanjar el asunto de la introspección o reflexión, pero hay poco más interesante por decir, casi todo lo demás es simplemente conocer los nombres de las funciones y aplicarlas, así pues, deberíamos pensar en cómo toda esta parafernalia nos puede resultar útil para crear un framework con PHP. Lo veremos en el siguiente artículo, que este ya es suficientemente largo.