Mostrando entradas con la etiqueta reflection. Mostrar todas las entradas
Mostrando entradas con la etiqueta reflection. Mostrar todas las entradas

lunes, 14 de mayo de 2007

Guardar propiedades static en $_SESSION (IV)

En esta tercera parte del artículo veremos la clase ClassStore.

Cada objeto ClassStore va a servir como un contenedor de las propiedades static de cada una de las clases utilizadas durante la ejecución del script. Todos estos objetos se van a guardar en un array indexado por el nombre de la clase: $_SESSION["__statics"][$nombre_de_la_clase]. El método estático __storeStatics (identico al código visto al final del último post) realiza estas acciones llamando a los métodos __getStatics() de las clases declaradas.


Para ello debemos hacer una lladama a __storeStatics cuando finalice la ejecución del script:

register_shutdown_function(array('ClassStore','__storeStatics'));

A continuación la clase ClassStore:

class ClassStore{
private $nombre;
private $statics;

function __construct($nombreClase,$statics){
$this->nombre=$nombreClase;
$this->statics=$statics;
}

function __wakeup(){
call_user_func(array($this->nombre,'__restoreStatics'),$this->statics);
}

static function __storeStatics(){
$classes=get_declared_classes();

foreach($classes as $name){
$reflejo=new ReflectionClass($name);

if($reflejo->hasMethod('__getStatics')){
$method=$reflejo->getMethod('__getStatics');

if($method->getDeclaringClass()->getName()===$name){

if(empty($_SESSION["__statics"]))
$_SESSION["__statics"]=array();

$_SESSION["__statics"][$name]=new ClassStore($name,call_user_func(array($name,'__getStatics')));

}
}
}
}
}

Si nos fijamos bien, cada vez que se recupere la sesion con session_start() el array $_SESSION se deserializa y se reconstruyen los objetos que guarda. Después de reconstruidos se llama al __wakeup de todos aquellos que lo tengan definido. De este modo cada unos de los objetos ClassStore devolverá a su valor anterior las propiedades static de cada una de las clases.

RECORDEMOS: en aquellas clases que queramos mantener estas propiedades debemos definir los métodos __getStatics y __restoreStatics como hemos visto. A continuación, en el script de cabecera, dónde tengamos el autoload de las clases y el session_start() registramos la llamada a la función __storeStatics para cuando finalice el script: register_shutdown_function(array('ClassStore','__storeStatics')). Y voilá, ya se mantienen las propiedades static.

Ir a... [I][II][III]

LEER MÁS……

viernes, 11 de mayo de 2007

Guardar propiedades static en $_SESSION (III)

Como había dicho en mi anterior post, en éste veremos el API de Reflexión con el que viene provisto el PHP 5.

Nuestro primer contacto con este API lo hemos tenido cuando definíamos la función __getStatics(), recordemos:



static function __getStatics(){
$statics=array();
$reflejo=new ReflectionClass(__CLASS__);
$properties=$reflejo->getProperties();

foreach($properties as $p) if($p->isStatic() &&
$p->getDeclaringClass()->getName()===__CLASS__ ) {

$nombre=$p->getName();
$valor=self::$$nombre;
if(!is_resource($valor)) $statics[$nombre]=$valor;
}
return $statics;
}

Como vemos el API nos sirve para obtener información de las clases que hay definidas. En este caso obtenemos el objeto ReflectionClass que representa a la clase en la que está definido éste método. El método getProperties() nos devuelve todas las propiedades en un array de objetos ReflectionProperty que representa a cada una de las propiedades de la clase.

Este array nos devuelve TODAS las propiedades, incluso las heredadas, por lo que tenemos que hacer una criba y seleccionar únicamente aquellas que están declaradas directamente en la clase, que sean static y no sean un recurso (ya que no tiene sentido guardarlos de una ejecucion a otra).

Como habíamos dicho éste método debemos definirlo en todas aquellas clases en las que queramos mantener valores static de una ejecución a otra del script, ahora bien debemos ver como llamar a este método de una forma automatizada:
$classes=get_declared_classes();

foreach($classes as $name){
$reflejo=new ReflectionClass($name);

if($reflejo->hasMethod('__getStatics')){
$method=$reflejo->getMethod('__getStatics');

if($method->getDeclaringClass()->getName()===$name){

if(empty($_SESSION["__statics"]))
$_SESSION["__statics"]=array();

$_SESSION["__statics"][$name]=new ClassStore($name,call_user_func(array($name,'__getStatics')));
}
}
}

Para cada una de las clases declaradas en el script comprobamos cuales de ellas tienen definido el método __getStatics (no heredado). Para cada una de esas clases se crea un objeto ClassStore al que se le pasan el array de valores de las propiedades static. Cada uno de estos objetos se guarda en $_SESSION["__statics"].

En el siguiente post veremos el objet ClassStore, que automatizará la recuperación de los datos de las propiedades static.

Ir a... [I][II][IV]

LEER MÁS……

jueves, 10 de mayo de 2007

Guardar propiedades static en $_SESSION (II)

Como contaba en mi anterior entrada al contrario del resto de propiedades de un objeto (almacenado en el array $_SESSION) las static, por pertenecer a la clase y no al objeto, no se recuperan con la llamada a la función session_start(). Exprimiendo un poco el coco llegué a una solución bastante eficiente y poco sangrante.



¿A que me refiero con poco sangrante?

Cuando se está buscando un parche, como en este caso, siempre hay que tragar con unas cuantas líneas de código extra. Lo más importante es que éste resulte localizable y que sea fácil de eliminar llegado el caso. El código que propongo se compone de una clase extra que actuará independientemente, y de dos método "mágicos" en cada clase que tenga propiedades static que deseemos mantener en session. Estos métodos son iguales para todas y son muy simples:

static function __restoreStatics($statics){
foreach($statics as $nombre=>$valor)
self::$$nombre=$valor;
}

static function __getStatics(){
$statics=array();
$reflejo=new ReflectionClass(__CLASS__);
$properties=$reflejo->getProperties();

foreach($properties as $p) if($p->isStatic() &&
$p->getDeclaringClass()->getName()===__CLASS__ ) {

$nombre=$p->getName();
$valor=self::$$nombre;
if(!is_resource($valor)) $statics[$nombre]=$valor;
}
return $statics;
}

¿Por qué son imprescindible estos métodos?

Sólo un método de la propia clase puede acceder las propiedades private y protected (en las primeras versiones, PHP 5 no era tan estricto). Cualquier posible solución tiene que contar con dos métodos definido en aquellas clases con propiedades static que queramos conservar.
Ojo: estos métodos no pueden ser heredados, hay que definirlos para cada clase. Veamos como funcionan:

  1. El método __getStatics apollado en un objeto ReflectionClass obtiene los atributos static de la clase (objetos ReflectionProperty). Comprueba que no se trata ni de un atributo heredado ni de un recurso y devuelve un array asociativo indexado por el nombre de cada atributo.

  2. El método __restoreStatics hace lo contrario, se le pasa el array de statics y vuelve establecer los atributos a los valores dados.


Por lo dicho ya vemos que el método __getStatics debería ser invocado cuando se finalice el script, almacenando el resultado que obtengamos para cada clase. Al contrario, el método __restoreStatics será llamado cuando se inicie la ejecución del script. Si prefieres puedes ver estos dos métodos como dos más de los "métodos mágicos", como __sleep o __wakeup, así no suena tan mal.

Con estos dos métodos ya casi tenemos solucionado todo el problema. En el siguiente post veremos con más detalle la API de Reflexión que parece va adquiriendo importancia en este problema.

Hasta el próximo
Ir a... [I][III][IV]

LEER MÁS……