miércoles, 25 de junio de 2025

Implementando Serialización Personalizada con `__sleep` y `__wakeup` en PHP

Implementando Serialización Personalizada con `__sleep` y `__wakeup` en PHP

La serialización en PHP permite convertir objetos en una cadena de bytes para su almacenamiento o transmisión. Aunque `serialize()` y `unserialize()` son funciones convenientes, a veces necesitamos un control más fino sobre qué propiedades se serializan y cómo se reconstruyen los objetos. Las funciones mágicas `__sleep()` y `__wakeup()` ofrecen este control, permitiendo la serialización personalizada.

El método `__sleep()` permite especificar un array de nombres de propiedades que deben ser serializadas. Si no se define, todas las propiedades del objeto serán serializadas. `__wakeup()` se ejecuta durante la deserialización y puede usarse para reestablecer conexiones de base de datos, recursos, o realizar cualquier inicialización necesaria.


class DatabaseConnection {
    private $host, $username, $password, $connection;

    public function __construct($host, $username, $password) {
        $this->host = $host;
        $this->username = $username;
        $this->password = $password;
        $this->connect();
    }

    private function connect() {
        $this->connection = mysqli_connect($this->host, $this->username, $this->password);
        if (!$this->connection) {
            die("Connection failed: " . mysqli_connect_error());
        }
    }

    public function query($sql) {
        return mysqli_query($this->connection, $sql);
    }

    public function __sleep() {
        // No serializamos la conexión directamente
        return array('host', 'username', 'password'); // Solo serializamos los datos para reconectar
    }

    public function __wakeup() {
        // Reconectamos a la base de datos cuando se deserializa el objeto
        $this->connect();
    }

    public function __destruct() {
        if($this->connection){
            mysqli_close($this->connection);
        }
    }
}

// Ejemplo de uso
$db = new DatabaseConnection("localhost", "user", "password");
$serialized = serialize($db);

// Destruimos el objeto original para simular la pérdida de la conexión
unset($db);

// Deserializamos el objeto.  __wakeup() se ejecutará aquí.
$db = unserialize($serialized);

// Ahora podemos usar la conexión deserializada
$result = $db->query("SELECT 1");
if ($result) {
    echo "Conexión restablecida y consulta exitosa!\n";
}
    

En este ejemplo, la conexión de base de datos (`$this->connection`) no se serializa directamente. En su lugar, `__sleep()` solo guarda la información necesaria para reconectar. Durante la deserialización, `__wakeup()` crea una nueva conexión, asegurando que el objeto deserializado pueda continuar funcionando correctamente. La inclusion de `__destruct()` asegura que al destruir una instancia, la conexion sea cerrada.


// Otro ejemplo simple para ilustrar __sleep con menos dependencias.
class User {
    public $username;
    private $password;
    private $token;

    public function __construct($username, $password) {
        $this->username = $username;
        $this->password = $password;
        $this->token = bin2hex(random_bytes(16)); // Genera un token aleatorio
    }

    public function __sleep() {
        // No serializamos el password ni el token
        return ['username']; // Solo serializamos el username
    }
}

$user = new User("testuser", "secret");
$serialized_user = serialize($user);
echo $serialized_user;
    

El ejemplo del Usuario demuestra una forma de proteger informacion sensible al no ser almacenada al serializar el objeto.

El uso de `__sleep()` y `__wakeup()` proporciona un mecanismo robusto para controlar el proceso de serialización, especialmente útil cuando se trabaja con recursos externos, información sensible o estados complejos dentro de los objetos.

No hay comentarios:

Publicar un comentario