miércoles, 25 de junio de 2025

PHP: Creando Streams de Datos Customizables con `stream_wrapper_register`

PHP: Creando Streams de Datos Customizables con `stream_wrapper_register`

PHP ofrece un sistema de streams poderoso que permite interactuar con diferentes fuentes de datos, como archivos, URLs o incluso memoria. Pero lo que muchos desarrolladores desconocen es la posibilidad de extender este sistema creando sus propios "stream wrappers". Estos wrappers permiten interceptar y modificar el comportamiento de las funciones estándar de PHP que trabajan con streams, como `fopen`, `fread`, `fwrite`, etc. Esto abre un mundo de posibilidades para trabajar con datos de maneras completamente customizadas, como acceso a bases de datos no convencionales, decodificación sobre la marcha, o cifrado transparente.

La función clave para esto es `stream_wrapper_register`. Esta función registra una clase PHP como un stream wrapper para un protocolo específico. La clase debe implementar un conjunto de métodos (especificados en la documentación de PHP) que definen el comportamiento del stream.


<?php

class MyCustomStream {

    private $position = 0;
    private $data = "Datos de prueba para mi stream customizado.";
    private $dat_length;

    public function stream_open($path, $mode, $options, & $opened_path) {
        echo "Abriendo stream: " . $path . "\n";
        $this->dat_length = strlen($this->data);
        return true;
    }

    public function stream_read($count) {
        echo "Leyendo " . $count . " bytes\n";
        $ret = substr($this->data, $this->position, $count);
        $this->position += strlen($ret);
        return $ret;
    }

    public function stream_write($data) {
        echo "Escribiendo: " . $data . "\n";
        // En este ejemplo, no implementamos escritura, pero podríamos hacerlo.
        return strlen($data); // Devolver el número de bytes escritos
    }

    public function stream_tell() {
        echo "Posición actual: " . $this->position . "\n";
        return $this->position;
    }

    public function stream_eof() {
        echo "EOF? ";
        return $this->position >= $this->dat_length;
    }

    public function stream_seek($offset, $whence) {
        echo "Buscando posición: " . $offset . " con whence: " . $whence . "\n";

        switch ($whence) {
            case SEEK_SET:
                $this->position = $offset;
                break;

            case SEEK_CUR:
                $this->position += $offset;
                break;

            case SEEK_END:
                $this->position = $this->dat_length + $offset;
                break;

            default:
                return false;
        }

        return true;
    }
}

stream_wrapper_register("mycustom", "MyCustomStream")
    or die("Falló registrar protocolo");

$fp = fopen("mycustom://data", "r+");
if ($fp) {
    echo fread($fp, 10) . "\n";
    echo fseek($fp, 5, SEEK_SET) . "\n";
    echo fread($fp, 10) . "\n";
    fclose($fp);
} else {
    echo "Falló abrir stream";
}

?>
    

En el ejemplo anterior, definimos una clase `MyCustomStream` que implementa los métodos básicos para un stream. Luego, registramos esta clase como el stream wrapper para el protocolo "mycustom". Esto significa que cuando intentemos abrir un stream con la URL "mycustom://data", PHP instanciará nuestra clase y llamará a sus métodos para manejar la operación.

Es importante tener en cuenta que la implementación de los métodos del stream wrapper debe ser cuidadosa, ya que errores en ellos pueden causar comportamientos inesperados en las funciones estándar de PHP. La documentación oficial de PHP proporciona detalles exhaustivos sobre los requisitos de cada método.

La creación de stream wrappers customizables ofrece una flexibilidad increíble para interactuar con datos de maneras no convencionales en PHP. Permite abstraer la complejidad de la fuente de datos subyacente, proporcionando una interfaz de stream limpia y consistente para el resto de la aplicación.

No hay comentarios:

Publicar un comentario