Стек буферов
Необходимо сделать несколько замечаний насчет функций "перехвата" выходного потока программы. Что получится, если больше одного раза подряд вызвать ob_start()? Хотя об этом не написано ни слова в официальной документации, рискну взять на себя ответственность и заявить, что, в общем-то, ничего нежелательного не произойдет. Последующие операторы вывода будут работать с тем буфером, который был установлен самым последним
вызовом. При этом функция ob_end_clean() не завершит буферизацию, а просто установит в активное состояние "предыдущий" буфер (разумеется, сохранив его предыдущее содержимое). Легче всего понять этот механизм на примере:
Листинг 30.15. Пример "перехвата" выходного потока
<?
ob_start(); // устанавливаем перехват в буфер 1
echo "1"// попадет в 1-й буфер
ob_start(); // откладываем на время буфер 1 и активизируем второй
echo "2"; // текст попадет в буфер 2
$A[2]=ob_get_contents(); // текст во втором буфере
ob_end_clean(); // отключает буфер 2 и активизируем первый
echo "1"; // попадет опять в буфер 1
$A[1]=ob_get_contents(); // текст в первом буфере
ob_end_clean(); // т.к. это последний буфер, буферизация отключается
// Распечатываем значения буферов, которые мы сохранили в массиве
foreach($A as $i=>$t) echo "$i: $t<br>";
// Выводится:
// 2: 2
// 1: 11
?>
Мы видим, что схема буферизации выходного потока чем-то похожа на стек: всегда используется тот буфер, который был активизирован последним. У такой схемы довольно много положительных черт, но есть и одна отрицательная. А именно, если какая-то логическая часть программы использует буферизацию выходного потока, но по случайности "забудет" вызвать ob_end_clean() перед своим завершением, оставшаяся программа останется "в недоумении", что же произошло. К сожалению, в PHP мы никак не сможем обойти это ограничение, так что призываю вас быть особенно внимательными.