Ob implicit flush: примеры (PHP)
ob_implicit_flush(bool $enable = true): voidФункция ob_implicit_flush() включает или выключает неявный сброс (flush) буфера вывода.
Использование этой функции делает ненужным вызов flush() после каждой операции записи в буфер вывода (например, с помощью echo или print). Включенный режим автоматически отправляет содержимое буфера на вывод после каждой операции, как будто после неё вызывается ob_flush().
Функция принимает один необязательный аргумент:
- $enable (bool): Если передано
true(или1), неявный сброс включается. Еслиfalse(или0), неявный сброс отключается. Значение по умолчанию -true.
Этот пример демонстрирует, как включить неявный сброс для пошагового вывода данных.
<?php
ob_implicit_flush(true); // Включаем неявный сброс
echo "Начало вывода...<br>";
for ($i = 1; $i <= 5; $i++) {
echo "Шаг $i...<br>";
sleep(1); // Пауза для наглядности
}
echo "Завершение.<br>";
?>Начало вывода...<br> (через 1 секунду) Шаг 1...<br> (через 2 секунды) Шаг 2...<br> (через 3 секунды) Шаг 3...<br> (через 4 секунды) Шаг 4...<br> (чезуз 5 секунд) Шаг 5...<br> Завершение.<br>
Пример отключения режима.
<?php
ob_implicit_flush(true); // Включаем
// ... какой-то код ...
ob_implicit_flush(false); // Выключаем
?>Для управления буферизацией вывода в PHP существует несколько функций.
- ob_start() - начинает буферизацию вывода. Без неё
ob_implicit_flush()может не дать ожидаемого эффекта. - ob_flush() - отправляет содержимое активного буфера вывода и отключает его. Эта функция выполняет сброс вручную.
- flush() - принудительно отправляет все буферизованные данные на вывод. Может не работать при использовании некоторых конфигураций веб-сервера или прокси.
- ob_end_flush() - отправляет содержимое буфера и завершает буферизацию.
Функцию ob_implicit_flush(1) удобно использовать для скриптов, которым требуется пошаговая отправка данных клиенту в реальном времени, например, для лонг-поллинга или вывода прогресса. Функции ob_flush() и flush() применяются для точечного, ручного управления сбросом буфера.
Ob implicit flush в Python
В Python веб-фреймворках (например, Flask) используется концепция генераторов или потоковой передачи для постепенной отправки данных.
from flask import Flask, Response
import time
app = Flask(__name__)
@app.route('/stream')
def stream_data():
def generate():
yield "Начало\n"
for i in range(5):
yield f"Данные {i}\n"
time.sleep(1)
yield "Конец"
return Response(generate(), mimetype='text/plain')
# Запуск: данные отправляются клиенту по мере готовности.В Node.js с помощью потоков (Streams) можно добиться аналогичного поведения.
const http = require('http');
http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('Начало\n');
let i = 0;
const interval = setInterval(() => {
res.write(`Данные ${i++}\n`);
if (i >= 5) {
clearInterval(interval);
res.end('Конец');
}
}, 1000);
}).listen(3000);
// Данные отправляются по частям каждую секунду.В отличие от PHP, где ob_implicit_flush() работает на уровне буфера вывода скрипта, в Python и Node.js управление потоком данных часто встроено в архитектуру фреймворков и осуществляется через объекты ответа или потоки, что является более низкоуровневым и контролируемым подходом.
Если буферизация вывода не была начата с помощью ob_start(), функция может не работать так, как ожидается.
<?php
ob_implicit_flush(true);
// ob_start(); // Буферизация НЕ включена!
echo "Этот текст может отправиться клиенту сразу, а не частями.";
?>Даже при корректном использовании функции вывод может буферизоваться на стороне веб-сервера (например, nginx с буферизацией fastcgi) или браузера.
Одновременное использование ob_implicit_flush() и функций вроде header() после вывода данных может привести к предупреждениям.
<?php
ob_implicit_flush(true);
echo "Некоторый вывод";
header('X-Custom: Value'); // Warning: Cannot modify header information - headers already sent
?>Начиная с PHP 8.0.0, параметр $enable функции ob_implicit_flush() стал строго типизированным. Теперь он ожидает значение типа bool. Передача целочисленных значений, таких как 0 или 1, по-прежнему возможна из-за автоматического приведения типов, но строгий режим (declare(strict_types=1)) вызовет ошибку TypeError при передаче не-bool значения.
<?php
declare(strict_types=1);
ob_implicit_flush(1); // TypeError: ob_implicit_flush(): Argument #1 ($enable) must be of type bool, int given
ob_implicit_flush(true); // Корректно
?>Функция полезна для отображения прогресса выполнения в CLI-скриптах.
<?php
ob_implicit_flush(true);
$total = 20;
echo "Прогресс: [" . str_repeat(" ", $total) . "]\r";
for ($i = 1; $i <= $total; $i++) {
usleep(100000); // 0.1 сек
echo "Прогресс: [" . str_repeat("#", $i) . str_repeat(" ", $total - $i) . "]\r";
}
echo "\nГотово!\n";
?>Прогресс: [####################] Готово!
Совместное использование с отключением сжатия и отправкой заголовков.
<?php
if (ob_get_level() == 0) ob_start();
ob_implicit_flush(true);
// Отключаем буферизацию на стороне сервера и клиента
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('X-Accel-Buffering: no'); // Для nginx
echo "data: Начало потока\n\n";
for ($i = 0; $i < 10; $i++) {
echo "data: Сообщение " . ($i + 1) . " - " . date('H:i:s') . "\n\n";
ob_flush(); // Дополнительный ручной сброс для надежности
flush();
sleep(1);
}
echo "data: Конец потока\n\n";
?>Функция влияет только на самый верхний уровень буфера.
<?php
ob_start(); // Буфер 1
ob_implicit_flush(true); // Включаем для буфера 1
echo "Уровень 1-1 ";
ob_start(); // Буфер 2 (вложенный)
ob_implicit_flush(false); // Отключаем для буфера 2
echo "Уровень 2 ";
ob_end_flush(); // Отправляем буфер 2, данные попадают в буфер 1
// На этом этапе "Уровень 2" еще не отправлен клиенту.
echo "Уровень 1-2 ";
ob_end_flush(); // Отправляем буфер 1, клиент получает всё сразу: "Уровень 1-1 Уровень 2 Уровень 1-2"
?>