Что вы не узнаете из документации, момент с дырой в безопасности + советы о том, как ускорить отклик сервера.
Буферизация вывода позволяет вам сохранять выходные данные PHP (в основном генерируемые echo, var_dump, print_r) в памяти (т.е. в буфере) вместо немедленной передачи в браузер или терминал. Что полезно для самых разных задач:
Предотвращение вывода "на экран":
ob_start(); // включает буферизацию $foo->bar(); // весь вывод этой строки идет только в буфер ob_end_clean(); // очищает буфер и закрывает буферизацию
Захватить вывод и записать в переменную: (Таким образом можно создавать кэш)
ob_start(); // включает буферизацию $foo->render(); // весь вывод этой строки идет только в буфер $output = ob_get_contents(); // сохраняет содержимое буфера в переменную ob_end_clean(); // очищает буфер и закрывает буферизацию
Функции ob_get_contents() и ob_end_clean() могут быть заменены одной функцией: ob_get_clean(), в ее имени больше нет "end" хотя фактически она отключает буферизацию вывода:
$output = ob_get_clean(); // сохраняет содержимое буфера в переменную и отключает буферизацию
В приведенных выше примерах полученный буфер не был отправлен на выход. Если вы хотите отправить его, используйте ob_end_flush() вместо ob_end_clean().
Чтобы получить содержимое буфера, отправить его на выход и отключить буферизацию, есть ещё одна функция (включая отсутствующий end в имени): ob_get_flush().
Буфер так же может быть очищен в любое время не выключая его, используя функцию ob_clean() (очищает буфер) или ob_flush() (отправляет буфер на выход):
ob_start(); // включает буферизацию $foo->bar(); // весь вывод этой строки идет только в буфер ob_clean(); // удаляет содержимое буфера, при этом не выключая буферизацию $foo->render(); // Весь этот вывод опять идет в буфер ob_flush(); // Отправить вывод буфера на выход $none = ob_get_contents(); // Содержимое буфера здесь пустая строка ob_end_clean(); // очищает буфер и закрывает буферизацию
В буфер также отправляются выходные данные, записанные в выход php://output, буферизацию можно избежать, записав в php://stdout (или STDOUT), который доступен только в CLI, т.е. при запуске скриптов из командной строки.
Гнездование (вложенные буферы)
Буферы могут быть вложенными, поэтому, когда один буфер активен, другой ob_start() активирует новый буфер. Таким образом, ob_end_flush() и ob_flush() на самом деле отправляют буфер не на выход, а в родительский буфер. И только при отсутствии родительского буфера содержимое отправляется в браузер или терминал.
Поэтому важно отключить буферизацию, даже если происходит исключение:
ob_start(); try { $foo->render(); } finally { finally доступен с PHP 5.5 ob_end_clean(); // или ob_end_flush() }
Размер буфера (chunk_size)
Буферизация также может улучшить производительность сервера, когда PHP не будет отправлять каждое echo в браузер, а вместо этого будет отправлять большие куски данных, например, по 4 кб. Просто вызовите в начале скрипта:
ob_start(null, 4096);
Когда размер буфера превышает 4096 байт, PHP автоматически выполняет flush, т.е. буфер очищается и отправляется. То же самое может быть достигнуто установкой директивы output_buffering, которая игнорируется в CLI.
Будьте осторожны , если вы начнете буферизацию без указания размера (то есть просто ob_start()), это приведет к тому, что страница будет отправляться не непрерывно, а один раз в конце скрипта, поэтому сервер будет реагировать очень медленно!
HTTP заголовки
Буферизация вывода не влияет на заголовки HTTP, они обрабатываются по-разному. Однако из-за буферизации вы можете отправлять заголовки даже после того, как выходные данные были отправлены, потому что они все еще находятся в буфере. Тем не менее, вы не должны полагаться на этот побочный эффект, потому что нет уверенности в том, что вывод не превышает размер буфера.
Дыра в безопасности
Когда скрипт PHP завершится, все ожидающие буферы запишут его содержимое в выход. Это можно вполне себе считать раздражающей дырой в безопасности. Если вы готовите в буфере конфиденциальные данные, которые не предназначены для вывода, и например, возникает ошибка, PHP записывает их в вывод. Решение состоит в том, чтобы использовать пользовательский обработчик:
ob_start ( function () { return '' ; });
Пользовательские обработчики
Вы можете установить свой собственный обработчик, т.е. функцию, которая будет обрабатывать содержимое буфера перед отправкой:
ob_start( function ($buffer, $phase) { return mb_strtoupper($buffer); } ); echo 'Привет'; ob_end_flush(); // выведет ПРИВЕТ
Также ob_clean() и ob_end_clean() вызывают обработчик, но отбрасывают вывод. Обработчик может определить, какая функция вызывается, и ответить на нее с помощью второго параметра $phase, который является битовой маской (начиная с PHP 5.4)
- PHP_OUTPUT_HANDLER_START когда буфер активирован
- PHP_OUTPUT_HANDLER_FINAL когда буфер отключен
- PHP_OUTPUT_HANDLER_FLUSH при вызове ob_flush() (но не ob_end_flush() или ob_get_flush())
- PHP_OUTPUT_HANDLER_CLEAN при вызове ob_clean(), ob_end_clean() или ob_get_clean()
- PHP_OUTPUT_HANDLER_WRITE при автоматическом flush
Этапы start, final и flush (так же clean) могут происходить одновременно. Это можно различить с помощью бинарного оператора &:
if ($phase & PHP_OUTPUT_HANDLER_START) { ... } if ($phase & PHP_OUTPUT_HANDLER_FLUSH) { ... } elseif ($phase & PHP_OUTPUT_HANDLER_CLEAN) { ... } if ($phase & PHP_OUTPUT_HANDLER_FINAL) { ... }
Является переводом статьи с phpfashion, здесь очень хорошо описана буферизация в PHP на английском языке. :)