Функция PHP flush(): немедленная отправка вывода в браузер
Узнайте, как PHP flush() отправляет буферизованный вывод в браузер немедленно, чем отличается от ob_flush() и когда её использовать.
По умолчанию PHP собирает текст, который выводит ваш скрипт (с помощью echo, print и т. д.), и отправляет его в браузер порциями — зачастую лишь после завершения скрипта. Встроенная функция flush() позволяет передать всё уже произведённое на данный момент прямо сейчас, чтобы пользователь видел частичный вывод ещё до того, как страница полностью сформирована. На этой странице объясняется, что делает flush(), чем она отличается от ob_flush(), какие буферы находятся между вашим скриптом и браузером, и когда её применение действительно помогает.
Что делает функция flush()
flush(): voidflush() просит PHP передать любой удерживаемый вывод нижестоящему слою — SAPI и веб-серверу. Функция не принимает аргументов и ничего не возвращает. Типичный сценарий использования — длительный скрипт, который должен отображать прогресс (строку лога, счётчик), а не заставлять пользователя смотреть на пустую страницу до завершения всех операций.
Два важных ограничения:
flush()не влияет на собственный слой буферизации вывода PHP (тот, что запускается с помощьюob_start()). Если буферизация вывода активна, текст по-прежнему заперт в буфере PHP, иflush()нечего отправлять. Сначала необходимо освободить этот слой с помощьюob_flush()илиob_end_flush().flush()не может переопределить буферизацию, выполняемую веб-сервером или прокси (Apachemod_deflate, Nginxproxy_buffering, FastCGI, gzip). Они всё равно могут удерживать данные, пока не решат их отправить.
Базовый пример
Если буферизация вывода PHP не включена, одного flush() достаточно для отправки текущего вывода:
<?php
echo "Starting a slow task...\n";
flush(); // send the line above to the browser now
sleep(2); // pretend we are doing real work
echo "Done!\n";
?>Без вызова flush() пользователь обычно увидит обе строки вместе — через 2 секунды. С ним строка "Starting a slow task..." может появиться немедленно.
flush() и ob_flush()
Именно здесь чаще всего возникает путаница. PHP может использовать два отдельных буфера, и каждая функция *flush работает с разным из них:
| Функция | Очищаемый буфер |
|---|---|
ob_flush() | Буфер управления выводом PHP (созданный ob_start()) → перемещает данные в буфер SAPI |
flush() | Буфер SAPI / записи → перемещает данные в направлении браузера |
Когда буферизация вывода включена, нужны обе функции — по порядку: сначала ob_flush(), чтобы освободить буфер PHP, затем flush(), чтобы продвинуть данные дальше:
<?php
ob_start(); // turn on PHP output buffering
echo "Buffered text\n";
ob_flush(); // PHP buffer -> SAPI buffer
flush(); // SAPI buffer -> browser
?>Если изменить порядок или пропустить ob_flush(), текст так и останется внутри PHP. Если вы хотите, чтобы PHP автоматически выполнял flush после каждого echo, см. ob_implicit_flush().
Почему это часто «не работает»
Надёжная потоковая передача вывода сложнее, чем вызов одной функции, потому что несколько слоёв выполняют буферизацию независимо:
- gzip / сжатие —
zlib.output_compressionи Apachemod_deflateдолжны накопить достаточное количество байт перед отправкой. Для ответов, которые вы хотите передавать потоком, отключите сжатие. - Буферизация веб-сервера / прокси — Nginx (
proxy_buffering on), FastCGI и балансировщики нагрузки обычно повторно буферизуют ответ. - Отрисовка браузером — некоторые браузеры ждут минимального количества байт перед отрисовкой; добавление дополнительных данных может принудить к более ранней отрисовке.
Из-за всего этого flush() лучше воспринимать как подсказку, а не гарантию. Для современных задач потоковой передачи (server-sent events, чанкованные API) настройте сервер явно, а не полагайтесь только на flush().
Связанные функции вывода
ob_flush()— очистить буфер управления выводом PHP.ob_end_flush()— очистить буфер и отключить буферизацию вывода.ob_get_flush()— вернуть содержимое буфера и очистить его.- PHP Output Control — обзор того, как слои буферизации взаимодействуют друг с другом.
fflush()— сбросить буферизованные записи в открытый файл (не в браузер).
Заключение
flush() принудительно отправляет уже произведённый PHP вывод в направлении браузера, не дожидаясь завершения скрипта. Помните, что функция затрагивает только буфер SAPI/записи: при активном ob_start() сначала необходимо вызвать ob_flush(), и даже в этом случае веб-сервер или слой сжатия может задержать доставку. При понимании этих ограничений flush() — удобный инструмент для потоковой передачи прогресса из длительных скриптов.