Функция PHP ob_flush(): всё, что нужно знать
Функция ob_flush() отправляет содержимое буфера вывода PHP на следующий уровень, оставляя буферизацию активной для дальнейшей работы.
По умолчанию PHP накапливает вывод в буфере и отправляет его клиенту за один раз. Иногда нужно передать уже накопленные данные в браузер, не закрывая буфер — например, чтобы построчно транслировать длинный отчёт или показывать прогресс во время долгой задачи. Функция ob_flush() делает именно это: она отправляет содержимое активного буфера вывода на следующий уровень и очищает его, оставляя буферизацию активной для дальнейшего сбора вывода. В этой главе объясняется, как ob_flush() вписывается в цепочку буферизации вывода PHP, когда её стоит использовать и какие подводные камни встречаются на практике.
Что делает ob_flush()
ob_flush() отправляет содержимое верхнего буфера вывода на следующий уровень — следующий буфер в стеке или внутренний слой записи PHP, если это единственный буфер. После сброса буфер очищается, но остаётся открытым, поэтому последующие echo снова будут перехватываться.
Signature: ob_flush(): void
Returns: nothing (void); emits a warning if no buffer is active
PHP: 4.0+ (return type became void in PHP 8.0)Две вещи легко перепутать:
ob_flush()перемещает данные из буфера PHP, но не гарантирует, что они достигнут браузера. Над ним может быть ещё один буфер, а также собственный буфер записи PHP и буфер веб-сервера.flush()проталкивает буферы записи PHP в сторону клиента. Чтобы байты действительно ушли по сети, обычно нужно вызвать оба в правильном порядке: сначалаob_flush(), затемflush().
Функцию необходимо использовать совместно с ob_start(). Вызов ob_flush() при отсутствии активного буфера вызывает notice/warning и ничего не делает.
Синтаксис
ob_flush();Функция не принимает аргументов и не возвращает значений.
Базовый пример
Включите буферизацию, выведите что-нибудь, а затем сбросьте буфер:
<?php
ob_start(); // 1. Enable output buffering
echo "This will be buffered";
ob_flush(); // 2. Flush PHP buffer to the next level
flush(); // 3. Push it toward the clientВывод:
This will be bufferedob_start() открывает буфер, echo захватывается в него, ob_flush() освобождает этот текст, а flush() подталкивает его к браузеру. Важно: буфер остаётся открытым после этого — можно снова делать echo и сбрасывать.
Потоковая передача вывода по частям
Наиболее распространённое реальное применение ob_flush() — отправка вывода кусками, чтобы пользователь видел результаты по мере их появления, а не ждал завершения всего скрипта:
<?php
ob_start();
for ($i = 1; $i <= 5; $i++) {
echo "Processing item $i\n";
ob_flush(); // hand this line to the next level
flush(); // and on toward the browser
// sleep(1); // (a real task would do work here)
}Вывод:
Processing item 1
Processing item 2
Processing item 3
Processing item 4
Processing item 5На реальном сервере с раскомментированным sleep(1) каждая строка появлялась бы с интервалом в одну секунду, а не всё сразу в конце.
ob_flush() vs. ob_end_flush() vs. ob_get_clean()
Выбор неверной функции сброса — обычная причина ошибок. Они отличаются по двум параметрам: остаётся ли буфер открытым и куда уходит содержимое.
| Функция | Отправляет содержимое? | Оставляет буфер открытым? |
|---|---|---|
ob_flush() | Да | Да — буферизация продолжается |
ob_end_flush() | Да | Нет — закрывает буфер |
ob_get_clean() | Нет — возвращает как строку | Нет — закрывает буфер |
Используйте ob_flush(), когда нужно выдавать прогресс, продолжая буферизацию. Используйте ob_end_flush(), когда работа полностью завершена. Используйте ob_get_clean(), когда нужно захватить содержимое буфера в переменную, а не отправлять его.
Распространённые подводные камни
- Серверная буферизация всё равно может задерживать вывод. Apache, Nginx (буферизация FastCGI), gzip-сжатие и прокси-серверы могут удерживать сброшенные байты, пока не накопится «достаточно».
ob_flush()+flush()управляют только стороной PHP. zlib.output_compressionнарушает потоковую передачу. При включённом gzip-сжатии вывода промежуточные сбросы обычно буферизуются для сжатия, поэтому чанки не будут передаваться постепенно. Отключите его для потоковых конечных точек.- Нет буфера — предупреждение. Вызов
ob_flush()без соответствующегоob_start()вызывает предупреждение. Проверьте активный уровень с помощьюob_get_level(), если не уверены. - Буфер очищается. После
ob_flush()буфер очищается, поэтому прочитать его предыдущее содержимое уже не получится. - Принудительная немедленная очистка глобально.
ob_implicit_flush(true)заставляет каждый оператор вывода сбрасываться автоматически, устраняя необходимость вызыватьob_flush()после каждогоecho.
Заключение
ob_flush() отправляет текущий буфер вывода на следующий уровень, оставляя буферизацию включённой, что делает её подходящим инструментом для постепенной передачи прогресса или больших ответов. Помните цепочку: ob_start() открывает буфер, ob_flush() передаёт его содержимое на следующий уровень, а flush() проталкивает их к клиенту — при этом серверная буферизация или gzip-сжатие всё равно могут задерживать доставку независимо от того, что делает ваш PHP-код.