为什么在PHP中使用输出缓冲?

amn*_*amn 27 php http

我在互联网上阅读了相当多的资料,不同的作者建议使用输出缓冲.有趣的是,大多数作者仅仅因为它允许将响应标题与实际内容混合而论证其使用.坦率地说,我认为负责任的Web应用程序不应混合输出标头和内容,Web开发人员应该在其脚本中查找可能的逻辑缺陷,这会导致在生成输出后发送标头.这是我对ob_*输出缓冲API的第一个参数.即使你得到的一点点便利 - 将标题与输出混合 - 使用它也不是一个足够的理由,除非你需要快速破解脚本,这通常不是严肃的Web应用程序中的目标或方式.

此外,我认为大多数处理输出缓冲API的人都没有考虑这样一个事实:即使没有启用显式输出缓冲,PHP与插入的Web服务器相结合,仍然会进行一些内部缓冲.很容易检查 - 做一些短串的回声,睡10秒,然后做另一个回声.使用浏览器请求您的脚本,并观察空白页暂停10秒,此后两行都出现.在有人说它是渲染假象而不是流量之前,跟踪客户端和服务器之间的实际流量表明服务器已经Content-Length为整个输出生成了具有适当值的标头 - 表明输出没有逐步发送echo调用,但在一些缓冲区中累积,然后在脚本终止时发送.这是我对显式输出缓冲的抱怨之一 - 为什么我们需要两个不同的输出缓冲区实现?可能是因为内部(不可访问的)PHP/Web服务器输出缓冲受PHP开发人员无法控制的条件限制,因此不可用?

在任何情况下,我为一,开始认为应该避免显式输出缓冲(系列ob_*函数)并依赖于隐式的flush,在必要时协助它具有良好的功能.也许如果Web服务器有一些保证在每次回显/打印调用时实际向客户端发送输出,那么设置显式缓冲会很有用 - 毕竟不希望向客户端发送大约100的响应字节块.但是有两个缓冲区的替代方案似乎是一个有点无用的抽象层.

那么,最终,严肃的Web应用程序是否需要输出缓冲?

Dav*_*ock 12

严重的Web应用程序在某种特定情况下需要输出缓冲:

您的应用程序希望控制某些第三方代码输出的内容,但没有API来控制该代码发出的内容.

在那种情况下,您可以ob_start()在将控制权交给该代码之前调用,弄乱所写的内容(理想情况下使用回调,或者如果必须,检查缓冲区内容), 然后 调用ob_flush().

最终,PHP的ob_ 函数是一种机制,用于捕获其他一些代码所做的事情可以搞砸的缓冲区.

如果您不需要检查或修改写入缓冲区的内容,则无需使用ob_start().

很可能,您的"严肃应用"实际上是某种框架.


无论如何,你已经有了输出缓冲

您不需要ob_start()为了使用输出缓冲.你的网络服务器已经缓冲你的产出.

使用ob_start()不会让你获得更好的输出缓冲 - 它实际上可以通过"囤积"数据来增加你的应用程序的内存使用和延迟,否则web服务器本来会发送给客户端.


也许ob_start()......

...为了方便冲洗时

在某些情况下,您可能需要根据应用程序最了解的某些条件来控制Web服务器何时刷新其缓冲区.大多数情况下,您知道您刚刚编写了一个客户端可以使用的逻辑"单元",并且您告诉Web服务器现在要刷新而不是等待输出缓冲区填满.要做到这一点,只需要正常发出输出,并用它标点flush().

更少见的是,在您有足够的数据发送之前,您需要保留来自Web服务器的数据.没有必要用一半的新闻来打断客户,特别是如果剩下的新闻需要一些时间才能获得.一个简单的ob_start后来的结论ob_end_flush()可能确实是最简单和适当的事情.

...如果您对某些标题负责

如果您的应用程序负责计算只能在完整响应可用后确定的标题,那么它可能是可接受的.

但是,即使在这里,如果你做的不是通过检查完整的输出缓冲区来获得头文件,那么你也可以让web服务器这样做(如果愿意的话).Web服务器的代码经过编写,测试和编译 - 您不太可能改进它.

例如,Content-Length如果应用程序在计算响应主体之前知道响应主体的长度,那么设置标头只会很有用.


没有灵丹妙药的坏习惯

你不应该ob_start()避免以下的纪律:

  • 打开,使用并快速关闭内存,线程和数据库连接等资源
  • 首先发射头部,然后是主体
  • 在开始响应之前,您可以执行所有计算和错误处理

如果你这样做,他们将导致技术债务,这将使你有一天哭.


Ark*_*rkh 9

好的,这是真正的原因:输出一切都没有开始.想象一个应用程序打开SQL连接,并在开始输出之前不关闭它.会发生什么是您的脚本获得连接,开始输出,等待客户端获得它所需要的所有内容,最后,关闭连接.Woot,2s连接,0.3s就足够了.

现在,如果缓冲,您的脚本连接,将所有内容放入缓冲区,最后自动断开连接,然后开始将生成的内容发送到客户端.

  • 咦!?如果加载结构需要2秒钟,那么页面出现严重错误.与DB的开放连接几乎没有影响.重要的是你经常建立这些联系以及你用它们做什么.-1 (3认同)

Dan*_*uis 5

如果要将报告输出到屏幕但也通过电子邮件发送,则输出缓冲使您无需重复处理以输出报告两次.


eye*_*ess 5

最明显的用例是:

  1. 输出过滤器(例如ob_gzhandler,您可以自己设计的任何数量的过滤器); 我用API支持输出(而不是返回值),我想用phpQuery这样的库进行后续解析.
  2. 用您讨论的所有问题编写的代码的维护(而不是重写); 这包括在输出开始后发送标题(信用Don Dickinson)或抑制已经生成的某些输出.
  3. 交错的输出(这里归功于汤姆和兰登); 请注意,您的测试可能会失败,因为它用PHP/Apache默认的内部缓冲冲突,但它可以做到的,它只是需要一定量的PHP之前被刷新会送什么,PHP将仍然保持连接打开,但.


Tom*_*Tom 1

我们过去常常将它用于具有非常长的表的页面,其中填充了数据库中的数据。您将每隔 x 行刷新缓冲区,以便用户知道页面实际上正在工作。然后有人听说了可用性,这样的页面得到了分页和搜索。