php - son - ¿Qué es una brigada de cubo?
funciones de las brigadas de emergencia (1)
¡Ah, bienvenidos a las partes menos documentadas del manual de PHP! [Abrí un informe de error al respecto; tal vez esta respuesta sea útil para documentarla: https://bugs.php.net/bug.php?id=69966 ]
La brigada del cubo
Para comenzar con su pregunta inicial, la brigada de cubetas es solo un nombre para el recurso llamado userfilter.bucket brigade
.
Se le pasaron dos brigadas diferentes como primer y segundo parámetro a php_user_filter::filter()
. La primera brigada es el grupo de entrada desde el que se lee, la segunda brigada está inicialmente vacía; le escribes
Con respecto a su actualización sobre la estructura de datos ... Es realmente una lista doblemente enlazada con cadenas básicamente. Pero bien puede ser que el nombre haya sido robado de allí ;-)
stream_bucket_prepend()
/ stream_bucket_append()
stream_bucket_prepend(resource $brigade, stdClass $bucket): null
stream_bucket_append(resource $brigade, stdClass $bucket): null
La $brigade
esperada es la brigada de salida, también conocida como el segundo parámetro en php_user_filter::filter()
.
El $bucket
es un objeto stdClass
como es devuelto por stream_bucket_make_writable()
o stream_bucket_new()
.
Estas dos funciones simplemente preceden o agregan el cubo pasado a la brigada.
stream_bucket_new()
Para desmitificar esta función, analice primero qué es su firma de función:
stream_bucket_new(resource $stream, string $buffer): stdClass
El primer argumento es la $stream
que estás escribiendo este cubo. El segundo es el $buffer
que contendrá este nuevo cubo.
[Me gustaría señalar aquí que el parámetro $stream
realidad no es muy significativo; solo se utiliza para comprobar si necesitamos asignar memoria de forma persistente para que sobreviva a través de las solicitudes. Supongo que puedes hacer que PHP sea muy bien de seguridad al pasar una secuencia persistente aquí, cuando operas en un filtro no persistente ...]
Ahora hay un recurso userfilter.bucket
creado que se asigna a una propiedad de un objeto ( stdClass
) llamado bucket
. Ese objeto también tiene otras dos propiedades: data
y data
, que contienen el búfer y el tamaño del búfer de este grupo.
Le devolverá un stdClass
que puede pasar a stream_bucket_prepend()
y stream_bucket_append()
.
stream_bucket_make_writable()
stream_bucket_make_writeable(resource $brigade): stdClass|null
Desplaza el primer cubo de la $brigade
y lo devuelve. Si la $brigade
se vació, devuelve null
.
Notas adicionales
Cuando se php_user_filter::filter()
, la propiedad $stream
en el objeto filter()
se establece en la secuencia en la que estamos trabajando actualmente. Ese es también el flujo que debe pasar a stream_bucket_new()
cuando lo llama. (La propiedad $stream
volverá a desactivar después de la llamada. No puede reutilizarla en, por ejemplo, php_user_filter::onClose()
).
También tenga en cuenta que incluso cuando se le devuelve una propiedad $datalen
, no necesita establecer esa propiedad en caso de que cambie $data
propiedad $data
antes de pasarla a stream_bucket_prepend()
o stream_bucket_append()
.
La implementación le requiere (bueno, espera que o le arroje una advertencia) que lea todos los datos del $in
bucket antes de regresar.
Hay otro caso de la documentación que nos miente: en php_user_filter::onCreate()
, la propiedad $stream
no está establecida. Solo se establecerá durante la llamada al método filter()
.
En general, no utilice filtros con flujos no bloqueantes. Lo intenté una vez y me salió terriblemente mal ... Y no es probable que alguna vez se arregle ...
Resumir (ejemplos)
Comencemos con el caso más simple: escribir lo que recibimos.
class simple_filter extends php_user_filter {
function filter($in, $out, &$consumed, $closing) {
while ($bucket = stream_bucket_make_writeable($in)) {
$consumed += $bucket->datalen;
stream_bucket_append($out, $bucket);
}
return PSFS_PASS_ON;
}
}
stream_filter_register("simple", "simple_filter")
Todo lo que sucede aquí es obtener cubos de $in
brigada de cangilones y volver a colocarlos dentro $out
brigada de cangilones.
Bien, ahora trata de manipular nuestra entrada.
class reverse_filter extends php_user_filter {
function filter($in, $out, &$consumed, $closing) {
while ($bucket = stream_bucket_make_writeable($in)) {
$consumed += $bucket->datalen;
$bucket->data = strrev($bucket->data);
stream_bucket_prepend($out, $bucket);
}
return PSFS_PASS_ON;
}
}
stream_filter_register("reverse", "reverse_filter")
Ahora registramos el protocolo reverse://
, que invierte su cadena (cada escritura se invierte por sí misma aquí; el orden de escritura aún se conserva). Por lo tanto, obviamente ahora necesitamos manipular los datos del depósito y anteponerlos aquí.
Ahora, ¿cuál es el caso de uso para stream_bucket_new()
? Por lo general, solo puede agregar a $bucket->data
; sí, incluso puede concatenar todos los datos en el primer depósito, pero cuando se flush()
es posible que no haya nada en la brigada del depósito y desee enviar un último depósito, entonces lo necesita.
class append_filter extends php_user_filter {
public $stream;
function filter($in, $out, &$consumed, $closing) {
while ($bucket = stream_bucket_make_writeable($in)) {
$consumed += $bucket->datalen;
stream_bucket_append($out, $bucket);
}
// always append a terminating /n
if ($closing) {
$bucket = stream_bucket_new($this->stream, "/n");
stream_bucket_append($out, $bucket);
}
return PSFS_PASS_ON;
}
}
stream_filter_register("append", "append_filter")
Con eso (y la documentación existente sobre la clase php_user_filter
), uno debería poder hacer todo tipo de filtrado de flujo de usuario mágico combinando todas estas posibilidades poderosas en un código aún más fuerte.
Realmente me encantaría implementar un php_user_filter::filter()
. Pero por eso tengo que saber qué es una brigada de cubo . Este parece ser un recurso que puedo operar con las funciones stream_bucket_*
. Pero la documentación no es realmente útil. Lo mejor que pude encontrar son esos ejemplos en stream_filter_register()
.
Estoy especialmente stream_bucket_new()
stream_bucket_make_writeable()
qué pueden hacer estos stream_bucket_new()
y stream_bucket_make_writeable()
.
Actualización: Parece que PHP está exponiendo una estructura de datos interna de Apache .