【问题标题】:What's the use of ob_start() in php?php中ob_start()有什么用?
【发布时间】:2011-05-23 01:32:28
【问题描述】:

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

【问题讨论】:

    标签: php output-buffering


    【解决方案1】:

    这是为了进一步澄清JD Isaaks answer ...

    您经常遇到的问题是您使用 php 从许多不同的 php 源输出 html,而这些源通常出于某种原因通过不同的方式输出。

    有时你有想要直接输出到浏览器的文字 html 内容;其他时候,输出是动态创建的(服务器端)。

    动态内容总是(?)将是一个字符串。现在,您必须将这个字符串化的动态 html 与任何文字、直接显示的 html ... 组合成一个有意义的 html 节点结构。

    这通常会迫使开发人员将所有直接显示的内容包装到一个字符串中(正如 JD Isaak 所讨论的那样),以便它可以与动态 html 一起正确交付/插入......即使你没有真的不想把它包起来。

    但是通过使用 ob_## 方法,您可以避免字符串包装的混乱。相反,文字内容输出到缓冲区。然后在一个简单的步骤中,将缓冲区的全部内容(所有文字 html)连接到您的动态 html 字符串中。

    (我的示例显示了将文字 html 输出到缓冲区,然后将其添加到 html-string ... 另请参阅 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>
    

    【讨论】:

      【解决方案2】:

      我使用它是为了摆脱 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>';
      ?>
      

      【讨论】:

      • 这可以用作在一个 PHP 中拥有多个 html 页面并通过 GET 调用它们的一种方式吗?
      • 我想是这样,但这听起来不是一个好主意。最好从单独的模板加载它们。
      • 请注意,此技术使用ob_get_clean(),而不是ob_end_clean()
      • 从来没有想过,这是一种对 IDE 非常友好的开发方式!另外,它消除了我需要在我的 PHP 中将 Javascript 或 HTML 作为字符串,不断转义 \" 等,这很烦人
      • 您的视觉效果清楚地展示了使用 ob_start 的好处。
      【解决方案3】:

      现有答案中未提及以下内容: 缓冲区大小配置 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

      【讨论】:

        【解决方案4】:

        此处接受的答案描述了 ob_start() 的作用——而不是使用它的原因(这是提出的问题)。

        如其他地方所述ob_start() 创建输出写入的缓冲区。

        但是没有人提到可以在 PHP 中堆叠多个缓冲区。见ob_get_level()。

        至于为什么……

        1. 将 HTML 以较大的块发送到浏览器可以从减少网络开销中获得性能优势。

        2. 以较大的块将数据从 PHP 中传递出来,通过减少所需的上下文切换次数来提高性能和容量

        3. 将更大的数据块传递给 mod_gzip/mod_deflate 会带来性能优势,因为压缩效率更高。

        4. 缓冲输出意味着您仍然可以稍后在代码中操作 HTTP 标头

        5. 在输出 [head]....[/head] 后显式刷新缓冲区可以允许浏览器在 HTML 流完成之前开始为页面编组其他资源。

        6. 在缓冲区中捕获输出意味着它可以重定向到其他功能,例如电子邮件,或作为内容的缓存表示复制到文件中

        【讨论】:

        • 重要提示:如果您在 PHP.ini 中启用了输出缓冲,则无需在页面上第一次调用 ob_start(),如下所示:output_buffering = 200000。在某些情况下(但不是全部),这种启用可以在 .htaccess 文件中完成,如下所示:php_value output_buffering 200000.
        【解决方案5】:

        我更喜欢:

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

        【讨论】:

        • 这是获取回显内容或 PHP 标记之外的内容的正确方法。如果您需要获得进一步的输出,您将需要一个最终的 ob_start 调用。
        【解决方案6】:

        想想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() , 分别停止保存并丢弃所有保存的内容,或停止保存并立即输出所有内容。

        【讨论】:

        • 很好的解释。我会更进一步,将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(); 这是正确的吗?如果不启用会怎样?
        • @Riley Dutton 你没说为什么使用 ob_start()
        • 遇到了同样的问题,在用ob_end_clean 修复了我的代码后,它就像一个魅力!谢谢@Riley Dutton
        • @Kevin Wheeler 如果在 PHP.ini 或 .htaccess 中未启用输出缓冲(有时但并非总是有效),并且之前没有完成 ob_start,则 ob_get_contents 将返回一个空字符串。输出最终可能会被刷新,它会显示为网页的输出。
        【解决方案7】:

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

        输出缓冲缓冲脚本的输出。这就是(简而言之)echoprint 之后的一切。带有标头的事情是,如果它们尚未发送,它们只能被发送。但是 HTTP 说,标头是传输的第一个。因此,如果您第一次(在请求中)输出某些内容,则会发送标头,并且您不能设置任何其他标头。

        【讨论】:

          【解决方案8】:

          你有它倒退。 ob_start 不缓冲标题,它缓冲内容。使用ob_start 可以让您将内容保存在服务器端缓冲区中,直到您准备好显示为止。

          这通常用于使页面可以在它们已经“发送”一些内容之后发送标题(即,决定在呈现页面的中途重定向)。

          【讨论】:

          • +1 我也对该函数的实际用法感到困惑。您关于在“重定向”期间使用它的回答让我想起了我遇到错误“标头已发送”的所有时间。谢谢
          【解决方案9】:

          此功能不仅适用于标题。你可以用它做很多有趣的事情。示例:您可以将页面拆分为多个部分并像这样使用它:

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

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

          【讨论】:

          • 这种看起来像我要找的。我需要将东西渲染到“部分”(想想 JS 和 CSS 文件),但我需要能够在模板中调用它们(它在标题之后加载)......所以如果我调用“$this- >addcss('specificCSStoThisView');"我希望它在 标签之间呈现。但是,我似乎无法用谷歌搜索。你能指出我正确的方向吗?谢谢!
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-10-01
          • 2011-02-19
          相关资源
          最近更新 更多