Why use output buffering in PHP?

2019-01-17 14:39发布

I have read quite a bit of material on Internet where different authors suggest using output buffering. The funny thing is that most authors argument for its use only because it allows for mixing response headers with actual content. Frankly, I think that responsible web applications should not mix outputting headers and content, and web developers should look for possible logical flaws in their scripts which result in headers being sent after output has been generated. This is my first argument against the ob_* output buffering API. Even for that little convenience you get - mixing headers with output - it is not a good enough reason to use it, unless one needs to hack up scripts fast, which is usually not the goal nor the way in a serious web application.

Also, I think most people dealing with the output buffering API do not think about the fact that even without the explicit output buffering enabled, PHP in combination with the web-server it is plugged into, still does some internal buffering anyway. It is easy to check - do an echo of some short string, sleep for say 10 seconds, and do another echo. Request your script with a browser and watch the blank page pause for 10 seconds, with both lines appearing thereafter. Before some say that it is a rendering artefact, not traffic, tracing the actual traffic between the client and the server shows that the server has generated the Content-Length header with an appropriate value for the entire output - suggesting that the output was not sent progressively with each echo call, but accumulated in some buffer and then sent on script termination. This is one of my gripes with explicit output buffering - why do we need two different output buffer implementations on top of one another? May it be because the internal (inaccessible) PHP/Web-server output buffering is subject to conditions a PHP developer cannot control, and is thus not really usable?

In any case, I for one, start to think one should avoid explicit output buffering (the series of ob_* functions) and rely on the implicit one, assisting it with the good flush function, when necessary. Maybe if there was some guarantee from the web server to actually send output to the client with each echo/print call, then it would be useful to set up explicit buffering - after all one does not want to send response to the client with some 100 byte chunks. But the alternative with two buffers seems like a somewhat useless layer of abstraction.

So, ultimately, do serious web applications need output buffering?

标签: php http
11条回答
一纸荒年 Trace。
2楼-- · 2019-01-17 15:27

I use output buffering in order to avoid generating HTML by string concatenation, when I need to know the result of a render operation to create some output before I use the rendering.

查看更多
闹够了就滚
3楼-- · 2019-01-17 15:35

Use output buffering to cache the data in a file, for other similar requests if you are doing a lot of database transactions and processing.

查看更多
冷血范
4楼-- · 2019-01-17 15:37

We used to use it back in the day for pages with enormously long tables filled with data from a database. You'd flush the buffer every x rows so the user knew the page was actually working. Then someone heard about usability and pages like that got paging and search.

查看更多
孤傲高冷的网名
5楼-- · 2019-01-17 15:38

Yes

Serious web applications need output buffering in one specific situation:

Your application wants control over what is output by some 3rd-party code, but there is no API to control what that code emits.

In that scenario, you can call ob_start() just before handing control to that code, mess around with what is written (ideally with the callback, or by examining the buffer contents if you must), and then calling ob_flush().

Ultimately, PHPs' ob_functions are a mechanism for capturing what some other bit of code does into a buffer you can mess with.

If you don't need to inspect or modify what is written to the buffer, there is nothing gained by using ob_start().

Quite likely, your 'serious application' is in fact a framework of some kind.


You already have output buffering, anyway

You don't need ob_start() in order to make use of output buffering. Your web-server already does buffer your output.

Using ob_start() does not get you better output buffering - it could in fact increase your application's memory usage and latency by 'hoarding' data which the web-server would otherwise have sent to the client already.


Maybe ob_start() ...

... for convenience when flushing

In some cases, you may want control over when the web-server flushes its buffer, based on some criteria which your application knows best. Most of the time, you know that you just finished writing a logical 'unit' which the client can make use of, and you're telling the web-server to flush now and not wait for the output buffer to fill up. To do this, it is simply necessary to emit your output as normal, and punctuate it with flush().

More rarely, you will want to withhold data from the web-server until you have enough data to send. No point interrupting the client with half of the news, especially if the rest of the news will take some time to become available. A simple ob_start later concluded by an ob_end_flush() may indeed be the simplest and appropriate thing to do.

... if you have responsibility for certain headers

If your application is taking responsibility for calculating headers which can only be determined after the full response is available, then it may be acceptable.

However, even here, if you can't do any better than deriving the header by inspecting the complete output buffer, you might as well let the web-server do it (if it will). The web-server's code, is written, tested, and compiled - you are unlikely to improve on it.

For example, it would only be useful to set the Content-Length header if your application knows the length of the response body after before it computes the response body.


No panacea for bad practices

You should not ob_start() to avoid the disciplines of:

  • opening, using and quickly closing resources such as memory, threads and database connections
  • emitting headers first, and the body second
  • doing all the calculations and error handling you can, before beginning the response

If you do these, they will cause technical debt which will make you cry one day.

查看更多
兄弟一词,经得起流年.
6楼-- · 2019-01-17 15:43

It's an old question but nobody said that an important feature of outbut buffering is filtering. It is possible to preprocess the buffer before sending it to the client.

This is a very powerful concept and opens many intriguing possibilities. In a project I used two filters simultaneously:

  1. ad-hoc translation of terms (replacement of short texts)
  2. obfuscation of HTML, CSS and Javascript (don't ask me why)

To enable output filtering call ob_start("callback") where callback is the name of the filtering function. For more details see PHP's manual for ob_start: http://php.net/manual/en/function.ob-start.php

查看更多
登录 后发表回答