Буферизация PHP-скриптов

В PHP имеется очень удобный механизм для буферизации вывода скриптов. В каких случаях это может понадобиться? Могу привести яркий жизненный пример. Допустим, есть некий сайт, который должен выдавать контент в кириллице или транслите, в зависимости от значения переключателя. Разумеется, создавать два различных подсайта для кириллицы и транслита - только время тратить. Правильнее всего сделать так: сайт генерирует контент только в кириллице, а перед отправкой страниц посетителю производится перекодировка в транслит, если это необходимо.

Как я сказал, лучше всего перекодировывать всю страницу за один раз - перед отправкой. Здесь работают два фактора: во-первых, при перекодировке всей страницы за один проход производится только один вызов функции транслитерации (но, очевидно, при этом тратится время на обработку разметки, которая и так записана латиницей), а во-вторых, если транслитерацию применять "кусочно" - только к кириллическим составляющим страницы - можно что-то да и пропустить. Так что, не надо сушить голову, а просто транслитеровать все за один раз. Возможные потери производительности с лихвой окупаются простотой кода.

Итак, мы подошли к тому, что нужно взять ВЕСЬ код страницы и обработать его за один раз. А как собрать весь код страницы в одно целое? Можно вместо echo ... и т.п. записать в начале скрипта $page = "";, а после всюду ставить: $page .= ... В итоге строка $page будет содержать весь код страницы. Но это неудобно. Т.к. тогда не удастся в скрипте делать простые html-вставки. Придется и их записывать как $page .= ... А вот применение буферизации позволяет писать скрипт, как обычно, с использованием как echo и т.п., так и простых html-вставок, но при этом ничего не будет отправляться посетителю до "ручного" сброса буфера, а код всей сгенерированной страницы можно получить в виде одной строки.

Еще один пример. Допустим, скрипт в процессе выполнения выдает какие-то HTTP-заголовки с помощью функции header() или устанавливает куки посредством setcookie(). Как известно, обе эти функции должны выполняться до того, как посетителю будет отправлен хотя бы один байт самой страницы. Поэтому, если генерирование заголовков или установка кук производятся под воздействием различных условий, сталкиваемся с возможным разрушением простого шаблона скрипта. И здесь буферизация окажет немедвежью услугу. Достаточно в начале скрипта включить буферизацию, а в его конце - сбросить буфер. И вызывать header() и setcookie() в этом случае можно уже в любом месте скрипта. Заголовки отправляются в обход буфера, и поэтому все они будут отправлены браузеру посетителя до момента отправки самой страницы.

Но перейдем к конкретике. По умолчанию буферизация выключена. Для управления ею имеются следующие функции (все они являются частью ядра PHP, поэтому для их использования не нужно производить никаких дополнительных действий):

Функция Описание Влияние на
буферизацию
void flush(void) Сброс всех буферов PHP, а также CGI, веб-сервера. -
void ob_clean(void) Очистка буфера. -
bool ob_end_clean(void) Очистка буфера. Возвращает логическое значение в зависимости от успешности выполнения операции. отключает
bool ob_end_flush(void) Сброс буфера. Возвращает логическое значение в зависимости от успешности выполнения операции. отключает
void ob_flush(void) Сброс буфера. -
string ob_get_clean(void) Получить содержимое текущего буфера и выключить буферизацию. Возвращает FALSE, если буферизация не была включена, иначе - строку с содержимым буфера. отключает
string ob_get_contents(void) Получить содержимое текущего буфера. Возвращает FALSE, если буферизация не была включена, иначе - строку с содержимым буфера. -
int ob_get_length(void) Возвращает длину содержимого буфера. -
int ob_get_level(void) Возвращает текущий уровень вложенности механизма буферизации. -
array ob_get_status([bool full_status]) Возвращает ассоциативный массив, содержащий информацию обо всех активных буферах, или FALSE, если таковые не имеются. -
string ob_gzhandler(string buffer [, int mode]) Callback-функция для использования с ob_start для сжатия вывода скрипта в формат gzip. Возвращает строку, представляющую собой gzip-сжатую строку buffer. -
void ob_implicit_flush([int flag]) Переключает режим буферизации (вкл/выкл). устанавливает буферизацию в состояние flag, либо, если flag не указан, переключает на противоположное
array ob_list_handlers(void) Возвращает массив, содержащий имена всех callback-функций, установленных в качестве обработчиков вывода скрипта. -
bool ob_start([callback output_callback]) Включает режим буферизации. Если передан параметр, устанавливает в качестве обработчика вывода скрипта функцию с указанным именем. Функция должна принимать строку и возвращать также строку. Вызов функции производится непосредственно перед сбросом буфера. При вызове функции передается строка с содержимым буфера. После выполнения тела функции в вывод скрипта будет направлена строка, возвращенная этой функцией. Возвращает логическое значение в зависимости от успешности выполнения операции. включает

Ну и теперь приведу два примера, касающиеся ситуаций, упомянутых в начале статьи.

Пример 1. Транслитерация вывода скрипта.Вариант 1.<? function transliter( $cyr_str) { ... } ob_start(); ГЕНЕРИРУЕТСЯ НЕКИЙ ВЫВОД СКРИПТА if (!$cyrillic) echo transliter(ob_get_clean()); else ob_end_flush(); ?> Вариант 2.<? function transliter( $cyr_str) { ... } ob_start(((!$cyrillic)?"transliter":"")); ГЕНЕРИРУЕТСЯ НЕКИЙ ВЫВОД СКРИПТА ob_end_flush(); ?> Пример 2. Отсылка заголовков.<? ob_start(); ТЕЛО СКРИПТА, В ТОМ ЧИСЛЕ ВЫЗОВЫ header() ob_end_flush();