En este post mostramos como simular el concepto de CAST de objetos en PHP.
Cast o Casting es un concepto de la programación orientada a objetos en que se aplica un operador a una variable para hacer una conversión explicita de tipo de variable.
En el caso de PHP soporta Cast para hacer que una variable de cierto tipo sea convertida a otro tipo de variable, pero manteniendo el valor de la variable. Por ejemplo, podemos convertir un string en un array:
<?php$foo = 'Hello World';
$var = (array) $foo;
print_r($var); // Debería mostrar array('Hello World')
?>
En el ejemplo anterior, utilizamos el operador "(array)" para convertir la variable de un string a un array. Este es el tipo de cast que nos permite realizar php.
El problema en php es que no permite el cast de objetos, es decir, tener un objeto de cierta clase y convertirlo en un objeto de otra clase, la cual herede de la clase anterior. Por ejemplo, podríamos tener una clase Vehiculo, de la cual extiende otra clase llamada Automovil. Si tenemos un objeto vivo del tipo Vehiculo, y queremos convertirlo en un objeto del tipo Automovil, no podemos hacer lo siguiente:
<?php$object = new Vehiculo();
$newObject = (Automovil) $object; // Esto nos arrojara un Fatal Error.
?>
El ejemplo de arriba nos arrojará un Error Fatal de PHP.
Para poder realizar la conversión entre objetos deseada en el ejemplo de arriba, podemos usar la siguiente función:
<?phpfunction cast($old_object, $new_classname){
if(class_exists($new_classname)){
$old_serialized_object = serialize($old_object);
$old_object_name_length = strlen(get_class($old_object));
$subtring_offset = $old_object_name_length + strlen($old_object_name_length) + 6;
$new_serialized_object = 'O:' . strlen($new_classname) . ':"' . $new_classname . '":';
$new_serialized_object .= substr($old_serialized_object, $subtring_offset);
$new_serialized_object = base64_encode($new_serialized_object);
return unserialize(base64_decode($new_serialized_object));
} else {
return false;
}
}
?>
Espero que les sea de utilidad.


9 Comentarios:
jtopo:
11 de Enero de 2010 a las 16:27:39Hola. Que utilidad tiene aplicar la función bas64_encode? No le veo sentido, ya que inmediatamente le aplicás base64_decode...
hasheado:
11 de Enero de 2010 a las 16:46:27Hola jtopo, lo de codificar y descodificar es para hacer una serialización y deserialización seguras, ya que de lo contrario los string que se generan al usar serialize, pueden arrojar fatal errors al querer deserializar. Saludos
mauricio:
08 de Febrero de 2010 a las 20:04:36No seria mejor que cada objeto implement getData y setData con arrays asociativos? extendiendo de la misma claseo o algo? asi lo hago yo.
mauricio:
08 de Febrero de 2010 a las 20:23:48No entendi lo de los base64, lo busque en internet pero no le veo sentido tampoco. Tal vez si fuera que el texto en base 64 viajara por un form o por un get sería útil por si el base64 se rompiera en el request o algo, pero si lo haces inmediatamente no tiene sentido creo. si no queres que tire errores creo que podes hacer: $new_serialized_object = @serialize($new_serialized_object); return @unserialize($new_serialized_object);
hasheado:
08 de Febrero de 2010 a las 20:41:59Hola Mauricio, antes q nada gracias por visitar el sitio y comentar, no te entendi bien a que te referis con lo de implementar getData y setData. En cuanto a lo de base64, no es que si no se codifica en base64 el script no funcione, tranquilamente funcionará sin utilizar esa codificación, pero yo la uso asi xq en algún momento use el script sin codificar la serialización y me arrojaba error, el cual se soluciono al usar base64. Un saludo.
mauricio:
08 de Febrero de 2010 a las 21:47:57Te comento que no es buena practica lo que haces: te adjunto un script que te muestra por que (espero que el editor no me lo corte). por otro lado fijate que aca lo uso sin hacer base64 y funciona perfectamente. class x1{ private $val1 = "x1::val1"; protected $val2 = "x1::val2"; public $val3 = "x1::val3"; private $val4 = "x1::val4"; protected $val5 = "x1::val5"; public function getXVal1(){ return($this->val1); } public function getXVal2(){ return($this->val2); } public function getXVal3(){ return($this->val3); } public function getXVal4(){ return($this->val4); } public function getXVal5(){ return($this->val5); } } class y1 extends x1{ private $val1 = "y1::val1"; public $val2 = "y1::val2"; public $val4 = "y1::val4"; protected $val5 = "x1::val5"; public function getYVal1(){ return($this->val1); } public function getYVal2(){ return($this->val2); } public function getYVal3(){ return($this->val3); } public function getYVal4(){ return($this->val4); } public function getYVal5(){ return($this->val5); } } function Cast($o, $class){ return(unserialize(preg_replace('/O:[0-9]+:"'.get_class($o).'":/', 'O:'.strlen($class).':"'.$class.'":', serialize($o), 1))); } $x = new x1(); $y = Cast($x, 'y1'); var_dump('getYVal1 returns '.$y->getYVal1()); var_dump('getXVal1 returns '.$y->getXVal1()); var_dump('getYVal2 returns '.$y->getYVal2()); var_dump('getXVal2 returns '.$y->getXVal2()); var_dump('getYVal3 returns '.$y->getYVal3()); var_dump('getYVal3 returns '.$y->getXVal3()); var_dump('getYVal4 returns '.$y->getYVal4()); var_dump('getXVal4 returns '.$y->getXVal4()); var_dump('getYVal5 returns '.$y->getYVal5()); var_dump('getXVal5 returns '.$y->getXVal5()); si lo ejecutas podes ver que se hace lio con las variables privadas. Lo que te comentaba del get / set data es esto. Yo uso en mis objetos un array donde meto todos los datos privados y uso las funciones magicas __call para hacer que getAlgo() me llame a la funcion getData('algo') que hace return $this->_misdatos['algo'], y para el set igual . En fin, lo que hago es guardar en un array, entonces puedo llenar los objetos de otras clases con la misma informacion haciendo esto: $x = new UnaClase(); $y = new OtraClase(); $y->setData($x->getData()); el metodo que usas me parece que no esta muy bueno por el hecho de que genera valores extraños y guardas en el objeto variables que no podes acceder, en ese caso si porque yo las derive, pero trata de accederlas sin que deriven. Obviamente si lo usas no lo vas a cambiar ahora, pero no es como para recomendarlo. saludos
hasheado:
09 de Febrero de 2010 a las 01:58:53Hola Mauricio ahi estuve probando tu script y esta muy bueno, desde ya te agradezco por el aporte. saludos
kernel32:
12 de Marzo de 2010 a las 01:38:37al final ... es o no buena practica hacer lo que haces ?? saludos diego
hasheado:
12 de Marzo de 2010 a las 01:56:09@kernel32: el cast de objetos no es soportado por PHP, este script es una manera de simularlo, asi que si es de utilidad y como puedes leer en los comentarios hay otras alternativas también de hacerlo. Saludos.