Saltar la navegación

1.4.- Mecanismos de mantenimiento del estado.

Dibujo de una persona sosteniendo un sobre gigante delante de un ordenador.
Negative Space (Dominio público)

En la unidad anterior aprendiste a usar la sesión del usuario para almacenar el estado de las variables, y poder recuperarlo cuando sea necesario. El proceso es muy sencillo; se utiliza el array superglobal $_SESSION, añadiendo nuevos elementos para ir guardando la información en la sesión.

El procedimiento para almacenar objetos es similar, pero hay una diferencia importante. Todas las variables almacenan su información en memoria de una forma u otra según su tipo. Los objetos, sin embargo, no tienen un único tipo. Cada objeto tendrá unos atributos u otros en función de su clase. Por tanto, para almacenar los objetos en la sesión del usuario, hace falta convertirlos a un formato estándar. Este proceso se llama serialización.

En PHP, para serializar un objeto se utiliza la función serialize(). El resultado obtenido es un string que contiene un flujo de bytes, en el que se encuentran definidos todos los valores del objeto.

$p = new Producto();
$a = serialize($p);

Esta cadena se puede almacenar en cualquier parte, como puede ser la sesión del usuario, o una base de datos. A partir de ella, es posible reconstruir el objeto original utilizando la función unserialize().

$p = unserialize($a);

Debes conocer

Las funciones serialize y unserialize se utilizan mucho con objetos, pero sirven para convertir en una cadena cualquier tipo de dato, excepto el tipo resource. Cuando se aplican a un objeto, convierten y recuperan toda la información del mismo, incluyendo sus atributos privados. La única información que no se puede mantener utilizando estas funciones es la que contienen los atributos estáticos de las clases.

Si simplemente queremos almacenar un objeto en la sesión del usuario, deberíamos hacer por tanto:

session_start();
$_SESSION['producto'] = serialize($p);

Pero en PHP esto aún es más fácil. Los objetos que se añadan a la sesión del usuario son serializados automáticamente. Por tanto, no es necesario usar serialize() ni unserialize().

session_start();
$_SESSION['producto'] = $p;

Para poder deserializar un objeto, debe estar definida su clase. Al igual que antes, si lo recuperamos de la información almacenada en la sesión del usuario, no será necesario utilizar la función unserialize.

session_start();
$p = $_SESSION['producto'];

Debes conocer

Como ya viste en el tema anterior, el mantenimiento de los datos en la sesión del usuario no es perfecta; tiene sus limitaciones. Si fuera necesario, es posible almacenar esta información en una base de datos. Para ello tendrás que usar las funciones serialize() y unserialize(), pues en este caso PHP ya no realiza la serialización automática.

En PHP además tienes la opción de personalizar el proceso de serialización y deserialización de un objeto, utilizando los métodos mágicos "__sleep()" y "__wakeup()". Si en la clase está definido un método con nombre "__sleep()", se ejecuta antes de serializar un objeto. Igualmente, si existe un método "__wakeup()", se ejecuta con cualquier llamada a la función unserialize().

Métodos mágicos __sleep() y __wakeup().

Para saber más

A partir de PHP7 se han implementado filtros para unserialize(): Esta característica busca el proporcionar una mejor seguridad al deserializar objetos en datos no fiables. Previene de posibles inyecciones de código al capacitar al desarrollador a crear listas blancas de clases que deben ser deserializadas.

// convertir todos los objetos a un objeto __PHP_Incomplete_Class
$data = unserialize($foo, [“allowed_classes” => false]);
// convertir todos los objetos a un objeto __PHP_Incomplete_Class excepto a los de MiClase y MiClase2
$data = unserialize($foo, [“allowed_classes” => [“MiClase”, “MiClase2”]]);
// comportamiento predeterminado (lo mismo que omitir el segundo argumento) que acepta todas las clases
$data = unserialize($foo, [“allowed_classes” => true]);

Autoevaluación

Pregunta

Si serializas un objeto utilizando serialize, ¿puedes almacenarlo en una base de datos MySQL?

Respuestas

Verdadero.

Falso.

Retroalimentación