Búfer de salida en PHP 7

El almacenamiento en búfer de salida es un mecanismo PHP que controla la salida de un script. Imagina que escribimos eco ‘prueba’; dentro de nuestro script PHP y no veo nada en la pantalla. ¿Cómo es eso posible? La respuesta es el buffering de salida.

El siguiente fragmento de código es un ejemplo simple de almacenamiento en búfer de salida:

<?php
ob_start();
sleep(2);
echo 'Chunk#1' . PHP_EOL;
sleep(3);
ob_end_flush();
ob_start();
echo 'Chunk#2' . PHP_EOL;
sleep(5);
ob_end_clean();
ob_start();
echo 'Chunk#3' . PHP_EOL;
ob_end_flush();
ob_start();
sleep(5);
echo 'Chunk#4' . PHP_EOL;
//Chunk#1
//Chunk#3
//Chunk#4

Cuando se ejecuta dentro del entorno CLI, primero veremos que sale Chunk # 1 después de unos segundos, luego, unos segundos después, veremos que sale Chunk # 3 y, finalmente, unos segundos más, veremos Chunk # 4 salir. El fragmento # 2 nunca se generará. Esto es todo un concepto, dado que estamos acostumbrados a que la construcción de echo genere cosas justo después de que se llame.

Existen varias funciones relacionadas con el búfer de salida, de las cuales las siguientes cinco son las más interesantes:

  • ob_start(): esto desencadena un nuevo búfer y crea búferes apilados si se llama después de otro búfer no cerrado
  • ob_end_flush(): Esto genera el búfer superior y apaga este búfer de salida
  • ob_end_clean(): esto limpia el búfer de salida y apaga el búfer de salida
  • ob_get_contents(): devuelve el contenido del búfer de salida
  • ob_gzhandler(): esta es la función de devolución de llamada para usar con ob_start(), para GZIP el búfer de salida

El siguiente ejemplo muestra los búferes apilados:

<?php
ob_start(); // BUFFER#1
sleep(2);
echo 'Chunk #1' . PHP_EOL;
ob_start(); // BUFFER#2
sleep(2);
echo 'Chunk #2' . PHP_EOL;
ob_start(); // BUFFER#3
sleep(2);
echo 'Chunk #3' . PHP_EOL;
ob_end_flush();
ob_end_flush();
sleep(2);
echo 'Chunk #4' . PHP_EOL;
ob_end_flush();
//Chunk #1
//Chunk #2
//Chunk #3
//Chunk #4

La salida completa aquí se retiene durante aproximadamente 8 segundos, después de lo cual las cuatro cadenas Chunk # … se emiten a la vez. Esto se debe a que la función ob_end_flush() es la única que envía la salida a la consola, mientras que la función ob_end_flush() simplemente cierra el búfer y lo pasa al búfer principal presente en el código.

El uso de la función ob_get_contents() puede agregar más dinámica al búfer de salida, como se muestra en el siguiente ejemplo:

<?php
$users = ['John', 'Marcy', 'Alice', 'Jack'];
ob_start();
foreach ($users as $user) {
echo 'User: ' . $user . PHP_EOL;
}
$report = ob_get_contents();
ob_end_clean();
ob_start();
echo 'Listing users:' . PHP_EOL;
ob_end_flush();
echo $report;
echo 'Total of ' . count($users) . ' users listed' . PHP_EOL;
//Listing users:
//User: John
//User: Marcy
//User: Alice
//User: Jack
//Total of 4 users listed

La función ob_get_content() nos permite tomar una representación en cadena del contenido almacenado en el búfer. Depende de nosotros elegir si queremos modificar más ese contenido, enviarlo o pasarlo a otras construcciones.
¿Cómo se aplica todo esto a las páginas web? Después de todo, estamos interesados en el rendimiento de nuestros scripts, principalmente, en el contexto de páginas web. Sin el almacenamiento en búfer de salida, el HTML se envía al navegador en fragmentos a medida que PHP avanza a través de nuestro script. Con el búfer de salida, HTML es enviado al navegador como una cadena al final de nuestro script.
Teniendo en cuenta que la función ob_start() acepta una función de devolución de llamada, podemos usar la función de devolución de llamada para modificar aún más la salida. Esta modificación puede ser cualquier cosa, ya sea forma de filtrado o incluso compresión.

El siguiente ejemplo demuestra el uso del filtrado de salida:

<?php
ob_start('strip_away');
echo '<h1>','Bummer', '</h1>';
echo '<p>', 'I felt foolish and angry about it!', '</p>';
ob_end_flush();
function strip_away($buffer)
{
$keywords = ['bummer', 'foolish', 'angry'];
foreach ($keywords as $keyword) {
$buffer = str_ireplace(
$keyword,
str_repeat('X', strlen($keyword)),
$buffer
);
}
return $buffer;
}
// Outputs:
// <h1>XXXXXX</h1><p>I felt XXXXXXX and XXXXX about it!</p>

Hoy en día, sin embargo, no es probable que escribamos este tipo de estructuras nosotros mismos, ya que las abstracciones del marco lo enmascaran para nosotros.

Comparte