Flush: примеры (PHP)

Работа с функцией flush в PHP 8
Раздел: Буферизация вывода
flush: void

Описание функции flush

Функция flush() принудительно отправляет все буферизованные данные на вывод клиенту (в браузер или другой вывод). Её основная задача — преодолеть буферизацию на разных уровнях: уровне PHP, веб-сервера (например, Nginx, Apache) или прокси.

Когда используется функция

Использование актуально в сценариях, где требуется передавать данные клиенту по мере их готовности, а не одним блоком в конце выполнения скрипта. Типичные случаи применения:

  • Отправка данных о долгих процессах (прогресс-бар).
  • Потоковая передача больших файлов или данных.
  • Создание эффекта «живого» обновления страницы (long-polling, Server-Sent Events).
  • Вывод логов выполнения прямо в браузер.
Аргументы функции

Функция flush() не принимает никаких аргументов. Синтаксис вызова прост: flush(): void.

Короткие примеры использования

Базовый пример с задержкой

Поэтапный вывод чисел с задержкой.

<?php
if (ob_get_level()) ob_end_clean(); // Отключаем буферизацию вывода
header('Content-Type: text/html; charset=utf-8');
for ($i = 1; $i <= 5; $i++) {
    echo "Шаг: $i<br>";
    flush(); // Отправляем данные клиенту
    sleep(1); // Задержка в 1 секунду
}
?>
Шаг: 1
(через 1 секунду)
Шаг: 2
(через 1 секунду)
Шаг: 3
... и так далее.
Использование с буферизацией вывода (ob_start)
<?php
ob_start(); // Включаем буферизацию вывода
?>
<p>Этот текст буферизирован.</p>
<?php
flush(); // Эта попытка ничего не отправит, так как буфер не очищен
ob_flush(); // Очищаем буфер вывода
flush(); // Теперь отправляем данные клиенту
?>

Этот текст буферизирован.

Похожие функции в PHP

В PHP существует несколько функций для работы с буферизацией вывода, которые могут использоваться вместе с flush() или вместо неё в зависимости от задачи.

Отправляет содержимое текущего буфера вывода (если он активен) и отключает его. В отличие от flush(), работает только с буфером PHP, а не с системными буферами. Часто используется в паре: ob_flush() очищает буфер PHP, а flush() пытается отправить данные далее.

Отправляет содержимое текущего буфера вывода и отключает буферизацию. Это комбинация ob_flush() и ob_end_clean().

Включает неявную очистку буфера. После вызова этой функции каждый оператор вывода (например, echo) автоматически выполняет очистку буфера, как если бы после него вызывался flush(). Удобно для скриптов, где данные нужно отправлять непрерывно.

<?php
ob_implicit_flush(true);
for ($i = 0; $i < 5; $i++) {
    echo $i . "<br>";
    sleep(1); // Данные будут отправляться после каждого echo
}
?>

Типичные ошибки

Буферизация на стороне веб-сервера

Самая распространённая проблема — flush() не работает из-за буферизации на уровне веб-сервера (например, mod_gzip в Apache) или прокси-сервера. Решение часто требует настройки сервера.

<?php
// Этот код может не работать из-за буферизации сервера
for ($i = 0; $i < 5; $i++) {
    echo "$i\n";
    flush();
    sleep(1);
}
?>
(Все данные выводятся разом через 5 секунд, а не по мере поступления)
Вывод до вызова flush()

Попытка вывести данные после отправки заголовков, запрещающих вывод.

<?php
header('Content-Type: text/plain');
flush(); // Отправляем заголовки
// ... долгий процесс
sleep(5);
echo "Данные"; // Этот вывод может не отобразиться, если соединение прервано
?>
Игнорирование уровня буферизации PHP

Забывают отключить или очистить буфер PHP (ob_start()), из-за чего flush() не отправляет данные.

<?php
ob_start();
echo "Начало.\n";
flush(); // Данные остаются в буфере PHP, отправки не происходит
ob_end_flush(); // Только теперь данные уйдут
?>

Изменения в последних версиях PHP

В PHP 8 функция flush() не претерпела изменений в своём поведении или синтаксисе. Она остаётся совместимой с предыдущими основными версиями PHP (7.x, 5.x). Основные принципы работы с буферизацией вывода сохраняются.

Изменения касаются в основном внутренней реализации и улучшения производительности ядра PHP, но не затрагивают API этой функции. Разработчикам, обновляющим код с PHP 5 на 7 или 8, не требуется вносить правки, связанные с использованием flush().

Расширенные примеры использования

Отправка больших файлов с прогрессом

Имитация отправки большого файла с выводом процентов выполнения.

Пример php
<?php
header('Content-Type: text/html; charset=utf-8');
ob_implicit_flush(true);
@ini_set('zlib.output_compression', 0);
@ini_set('implicit_flush', 1);

$fileSize = 1024 * 1024 * 10; // 10 MB
$chunkSize = 1024 * 64; // 64 KB
$totalChunks = ceil($fileSize / $chunkSize);

for ($i = 0; $i < $totalChunks; $i++) {
    // Имитация чтения и отправки чанка данных
    echo str_repeat('.', $chunkSize / 1024); // Упрощённая имитация данных
    $progress = round(($i + 1) / $totalChunks * 100);
    echo "<script>document.getElementById('progress').innerHTML = '$progress%';</script>";
    flush();
    usleep(10000); // Небольшая задержка для наглядности
}
?>
<div id="progress">0%</div>
Long-polling для обновления данных

Пример простого long-polling механизма для получения уведомлений о новых событиях.

Пример php
<?php
// server.php
header('Content-Type: text/plain; charset=utf-8');
set_time_limit(0); // Отключаем ограничение времени выполнения

$lastCheck = $_GET['timestamp'] ?? time();
$maxWait = 30; // Максимальное время ожидания (секунд)

$startTime = time();
while (time() - $startTime < $maxWait) {
    // Проверяем наличие новых событий (например, в БД или файле)
    $hasNewEvents = checkForNewEvents($lastCheck);
    if ($hasNewEvents) {
        echo json_encode(['event' => 'Новое уведомление', 'timestamp' => time()]);
        flush();
        break;
    }
    sleep(1); // Пауза между проверками
}

if (!connection_aborted()) {
    echo json_encode(['event' => 'timeout']);
    flush();
}

function checkForNewEvents($since) {
    // Логика проверки новых событий
    return rand(0, 10) > 8; // Случайная имитация события
}
?>
Стриминг данных в реальном времени для дашборда

Передача данных для обновления графика на веб-странице.

Пример php
<?php
// stream.php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('X-Accel-Buffering: no'); // Отключение буферизации для Nginx
ob_end_clean(); // Очистка всех буферов

while (true) {
    $data = ['time' => date('H:i:s'), 'value' => rand(1, 100)];
    echo "data: " . json_encode($data) . "\n\n";
    flush();
    if (connection_aborted()) break;
    sleep(2); // Отправка данных каждые 2 секунды
}
?>
Пример php
<!-- client.html -->
<script>
const evtSource = new EventSource("stream.php");
evtSource.onmessage = function(event) {
    const data = JSON.parse(event.data);
    console.log(`Время: ${data.time}, Значение: ${data.value}`);
    // Логика обновления графика...
};
</script>

Альтернативы в других языках

Flush в Python

В веб-фреймворках Python, таких как Flask или Django, для потоковой передачи используется генератор или специальный потоковый ответ. Прямого аналога flush() в чистом виде нет.

# Пример с Flask и генератором
from flask import Flask, Response
import time

app = Flask(__name__)

@app.route('/stream')
def stream_data():
    def generate():
        for i in range(5):
            yield f"Данные: {i}\n"
            time.sleep(1)
    return Response(generate(), content_type='text/plain')

if __name__ == '__main__':
    app.run()
JavaScript (Node.js)

В Node.js с фреймворком Express для потоковой передачи используется объект response. Метод write() позволяет отправлять части ответа.

const express = require('express');
const app = express();

app.get('/stream', (req, res) => {
    res.writeHead(200, {
        'Content-Type': 'text/plain; charset=utf-8',
        'Transfer-Encoding': 'chunked'
    });
    let counter = 0;
    const interval = setInterval(() => {
        res.write(`Чанк данных: ${counter}\n`);
        counter++;
        if (counter >= 5) {
            clearInterval(interval);
            res.end();
        }
    }, 1000);
});

app.listen(3000);

Flush в MySQL

Прямого аналога для отправки данных клиенту в MySQL не существует. Однако для длительных операций можно использовать пошаговую выборку данных.

PHP flush function comments

En
Flush Flush system output buffer