php中的ob_start()有什么用?


298

ob_start()用于output buffering使头被缓冲,而不是发送到浏览器?我在这里有意义吗?如果不是,那我们为什么要使用ob_start()

Answers:


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)
Con Antonakos

我假设必须以.ini文件顺序启用输出缓冲才能调用ob_start();这是正确的吗?如果未启用该怎么办?
凯文·惠勒

5
@Riley Dutton您没有告诉我们为什么要使用ob_start()
Vishnu R Nair

修复了我的代码后,遇到了同样的问题,ob_end_clean就像一个魅力!感谢@Riley Dutton
Martins

160

我使用它,因此我可以使用大量HTML打破PHP,但不呈现它。它使我免于将其存储为禁用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
可以将其用作在一个PHP中包含多个html页面并通过GET调用它们的方法吗?
joshkrz 2012年

1
我想是这样,但这听起来不是一个好主意。最好从单独的模板加载它们。
JD Isaacks

1
请注意,此技术使用ob_get_clean(),而不是ob_end_clean()
Blazemonger

11
没想到,这是IDE友好的开发方式!另外,它消除了我在PHP中将Javascript或HTML作为字符串,不断转义\“等
的麻烦

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从许多不同的php来源输出html,而无论出于何种原因,这些来源通常都是通过不同的方式输出的。

有时,您有一些文字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.';

您可以捕获此处生成的输出,并将其添加到布局中两个完全不同的位置。


这种看起来像我要找的东西。我需要将内容渲染为“ sections”(例如JS和CSS文件),但是我需要能够在模板中调用它们(模板的加载时间晚于标题)...因此,如果我调用“ $ this- > addcss('specificCSStoThisView');“ 我希望它在<head>标签之间呈现。不过,我似乎无法在Google上找到它。你能指出我正确的方向吗?谢谢!
NoobishPro 2015年

2

现有答案中未提及以下内容:缓冲区大小配置HTTP标头和嵌套。

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将发送更大的数据块,例如4KB(不带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

不,你错了,但方向合适;)

Output-Buffering缓冲脚本的输出。多数民众赞成在(echo或之后)print。标头的问题是,如果尚未发送,则只能发送它们。但是HTTP表示,标头是传输的头一个。因此,如果您第一次(在请求中)输出某些内容,则将发送标头,并且您无法设置任何其他标头。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.