Какая польза от ob_start () в php?


298

Является ли ob_start()использовать для output bufferingтак, чтобы заголовки в буфер и не передаются в браузер? Имею ли я здесь смысл? Если нет, то почему мы должны использовать ob_start()?

Ответы:


481

Думайте о том, ob_start()как сказать: «Начни вспоминать все, что обычно выводится, но пока не делай с этим ничего».

Например:

ob_start();
echo("Hello there!"); //would normally get printed to the screen/output to browser
$output = ob_get_contents();
ob_end_clean();

Есть две другие функции, с которыми вы обычно связываете его:, ob_get_contents()который в основном дает вам все, что было «сохранено» в буфере с момента его включения ob_start(), и затем ob_end_clean()или ob_flush(), который либо прекращает сохранять вещи и сбрасывает то, что было сохранено, либо прекращает сохранение и выводит все сразу, соответственно.


55
Отличное объяснение. Я хотел бы пойти на один шаг дальше и заменить ob_get_contents()с ob_get_clean()и удалить , ob_end_clean()так как по ob_get_clean()существу , выполняет обе функции. Ссылка: php.net/manual/en/function.ob-get-clean.php (PHP 4> = 4.3.0, PHP 5)
Кон Антонакос,

Я предполагаю, что буферизация вывода должна быть включена в порядке файла INI для вызова ob_start();Это правильно? Что произойдет, если он не включен?
Кевин Уилер

5
@Riley Dutton Вы не говорите, почему используется ob_start ()
Вишну Р Наир

Была такая же проблема, после исправления моего кода с ob_end_cleanним работает как шарм! Спасибо @Riley Даттон
Мартинс

160

Я использую это, чтобы вырваться из PHP с большим количеством HTML, но не отображать его. Это спасает меня от сохранения в виде строки, которая отключает цветовое кодирование IDE.

<?php
ob_start();
?>
<div>
    <span>text</span>
    <a href="#">link</a>
</div>
<?php
$content = ob_get_clean();
?>

Вместо того:

<?php
$content = '<div>
    <span>text</span>
    <a href="#">link</a>
</div>';
?>

1
Можно ли это использовать как способ иметь несколько HTML-страниц в одном PHP и вызывать их через GET?
joshkrz

1
Полагаю, что так, но это не очень хорошая идея. Было бы лучше загрузить их из отдельных шаблонов.
Джей Ди Айзекс

1
Обратите внимание, что эта техника использует ob_get_clean(), а не ob_end_clean()
Blazemonger

11
Никогда не задумывался об этом, это невероятно дружественный IDE способ развития! Кроме того, это избавляет меня от необходимости иметь Javascript или HTML как строку в моем PHP, постоянно экранирующуюся \ "и т. Д.,
Что

1
Ваше визуальное представление дает четкое представление о преимуществах использования ob_start.
Klewis

86

Принятый ответ здесь описывает, что ob_start()делает, а не почему он используется (который был задан вопрос).

Как указано в другом месте, ob_start()создается буфер, в который записывается вывод.

Но никто не упомянул, что в PHP можно размещать несколько буферов. Смотрите ob_get_level ().

Что касается того, почему ....

  1. Отправка HTML-кода в браузер большими порциями дает выигрыш в производительности благодаря уменьшению нагрузки на сеть.

  2. Передача данных из PHP большими блоками дает выигрыш в производительности и емкости за счет уменьшения количества необходимых переключений контекста

  3. Передача больших массивов данных в mod_gzip / mod_deflate дает выигрыш в производительности, поскольку сжатие может быть более эффективным.

  4. буферизация вывода означает, что вы все еще можете манипулировать заголовками HTTP позже в коде

  5. явное очищение буфера после вывода [head] .... [/ head] может позволить браузеру начать маршалинг других ресурсов для страницы до завершения потока HTML.

  6. Захват вывода в буфер означает, что он может быть перенаправлен на другие функции, такие как электронная почта, или скопирован в файл в качестве кэшированного представления содержимого.


29

У тебя это задом наперед. ob_start не буферизует заголовки, он буферизует содержимое. Использование ob_startпозволяет вам хранить содержимое в буфере на стороне сервера, пока вы не будете готовы его отобразить.

Это обычно используется для того, чтобы страницы могли отправлять заголовки после того, как они «отправили» уже некоторый контент (то есть, решили перенаправить на полпути при рендеринге страницы).


3
+1 Меня тоже смутило фактическое использование функции. Ваш ответ относительно его использования во время «перенаправления» напомнил мне обо всех случаях, когда у меня была ошибка «Заголовки уже отправлены». Спасибо
погладить

13

Я предпочитаю:

ob_start();
echo("Hello there!");
$output = ob_get_clean(); //Get current buffer contents and delete current output buffer

8

это для дальнейшего уточнения JD Isaaks ответ ...

Проблема, с которой вы часто сталкиваетесь, заключается в том, что вы используете php для вывода html из разных источников php, и эти источники часто по какой-либо причине выводятся разными способами.

Иногда у вас есть буквальный HTML-контент, который вы хотите напрямую выводить в браузер; в других случаях вывод создается динамически (на стороне сервера).

Динамический контент всегда (?) Будет строкой. Теперь вам нужно объединить этот строковый динамический html с любым буквальным html, предназначенным для непосредственного отображения ... в одну значимую структуру html-узла.

Это обычно вынуждает разработчика заключать весь этот контент для отображения в строку (как обсуждал JD Isaak), чтобы его можно было правильно доставлять / вставлять в сочетании с динамическим html ... даже если вы на самом деле этого не делаете хочу обернуть.

Но, используя методы ob _ ##, вы можете избежать этой путаницы. Литеральное содержимое вместо этого выводится в буфер. Затем одним простым шагом все содержимое буфера (все ваши литералы html) объединяются в вашу строку dynamic-html.

(Мой пример показывает, что литеральный html выводится в буфер, который затем добавляется в html-строку ... посмотрите также на пример JD Isaaks, чтобы увидеть string-wrapping-of-html).

<?php // parent.php

//---------------------------------
$lvs_html  = "" ;

$lvs_html .= "<div>html</div>" ;
$lvs_html .= gf_component_assembler__without_ob( ) ;
$lvs_html .= "<div>more html</div>" ;

$lvs_html .= "----<br/>" ;

$lvs_html .= "<div>html</div>" ;
$lvs_html .= gf_component_assembler__with_ob( ) ;
$lvs_html .= "<div>more html</div>" ;

echo $lvs_html ;    
//    02 - component contents
//    html
//    01 - component header
//    03 - component footer
//    more html
//    ----
//    html
//    01 - component header
//    02 - component contents
//    03 - component footer
//    more html 

//---------------------------------
function gf_component_assembler__without_ob( ) 
  { 
    $lvs_html  = "<div>01 - component header</div>" ; // <table ><tr>" ;
    include( "component_contents.php" ) ;
    $lvs_html .= "<div>03 - component footer</div>" ; // </tr></table>" ;

    return $lvs_html ;
  } ;

//---------------------------------
function gf_component_assembler__with_ob( ) 
  { 
    $lvs_html  = "<div>01 - component header</div>" ; // <table ><tr>" ;

        ob_start();
        include( "component_contents.php" ) ;
    $lvs_html .= ob_get_clean();

    $lvs_html .= "<div>03 - component footer</div>" ; // </tr></table>" ;

    return $lvs_html ;
  } ;

//---------------------------------
?>

<!-- component_contents.php -->
  <div>
    02 - component contents
  </div>

4

Эта функция не только для заголовков. Вы можете сделать много интересного с этим. Пример: вы можете разбить свою страницу на разделы и использовать ее следующим образом:

$someTemplate->selectSection('header');
echo 'This is the header.';

$someTemplate->selectSection('content');
echo 'This is some content.';

Вы можете захватить сгенерированный здесь вывод и добавить его в двух совершенно разных местах макета.


Этот вид выглядит как то, что я ищу. Мне нужно визуализировать вещи в «секции» (подумайте о файлах JS и CSS), но мне нужно иметь возможность вызывать их внутри шаблона (который загружается позже, чем заголовок) ... Так что, если я назову «$ this- > addcss ( 'specificCSStoThisView');» Я хочу, чтобы он отображался между тегами <head>. Я не могу гуглить это, однако. Не могли бы вы указать мне правильное направление? Спасибо!
NoobishPro

2

Следующие вещи не упомянуты в существующих ответах: Конфигурация размера буфера HTTP Header и Nesting.

Настройка размера буфера для ob_start:

ob_start(null, 4096); // Once the buffer size exceeds 4096 bytes, PHP automatically executes flush, ie. the buffer is emptied and sent out.

Приведенный выше код повышает производительность сервера, так как PHP будет отправлять большие куски данных, например, 4 КБ (без вызова ob_start, php отправляет каждое эхо-сообщение в браузер).

Если вы начнете буферизацию без размера чанка (т.е. простого ob_start ()), то страница будет отправлена ​​один раз в конце скрипта.

Буферизация вывода не влияет на заголовки HTTP, они обрабатываются по-разному. Однако из-за буферизации вы можете отправлять заголовки даже после того, как выходные данные были отправлены, потому что они все еще находятся в буфере.

ob_start();  // turns on output buffering
$foo->bar();  // all output goes only to buffer
ob_clean();  // delete the contents of the buffer, but remains buffering active
$foo->render(); // output goes to buffer
ob_flush(); // send buffer output
$none = ob_get_contents();  // buffer content is now an empty string
ob_end_clean();  // turn off output buffering

Хорошо объяснено здесь: https://phpfashion.com/everything-about-output-buffering-in-php


0

Нет, вы не правы, но направление подходит;)

Буферизация вывода буферизует вывод скрипта. Вот (короче) все после echoили print. Проблема с заголовками в том, что они могут быть отправлены, только если они еще не отправлены. Но HTTP говорит, что заголовки - это самая первая передача. Поэтому, если вы выводите что-то впервые (в запросе), заголовки отправляются, и вы не можете устанавливать другие заголовки.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.