W3docs

PHP Output Control Functions: Everything You Need to Know

Learn PHP output buffering and the ob_* output control functions: ob_start, ob_get_clean, ob_end_flush, callbacks, and common gotchas, with runnable examples.

Normally, every echo, print, or piece of HTML in a PHP script is sent to the browser the moment it runs. Output buffering lets you intercept that output and hold it in memory (a buffer) instead, so you can inspect, edit, discard, or send it later. PHP's output control functions are the built-in tools that manage this buffer.

This chapter explains what output buffering is, why it solves real problems, and how each ob_* function works — with runnable examples.

Why output buffering matters

Output buffering is more than a curiosity. It solves a handful of everyday PHP problems:

  • Avoid "headers already sent" errors. In PHP you must call header() and setcookie() before any output reaches the browser. Buffer the output and you can still send headers after your templates have run, because nothing has actually been flushed yet. See headers_sent().
  • Capture output as a string. Render a template or include a file and grab its result as a variable instead of printing it — the foundation of most simple templating engines.
  • Post-process the whole page. Minify HTML, replace placeholders, or compress output (gzip) in one place before it's sent.
  • Discard unwanted output. Throw away noise from a third-party library or a debug statement you don't want the user to see.

The output control functions

Here are the functions you will use most. They all operate on the buffer started by ob_start().

FunctionWhat it does
ob_start()Starts a new output buffer. Capturing begins from this point.
ob_get_contents()Returns the buffer's current contents without stopping buffering.
ob_get_length()Returns the number of bytes currently in the buffer.
ob_get_level()Returns the nesting level (how many buffers are stacked).
ob_clean()Empties the buffer but keeps buffering on.
ob_get_clean()Returns the contents and turns the buffer off — a common combo.
ob_end_clean()Discards the buffer and turns buffering off (returns nothing).
ob_flush() / ob_end_flush()Sends the buffer to the browser; ob_end_flush() also stops buffering.

Capture output as a string

The most common use of buffering is grabbing whatever a block of code prints and storing it in a variable. ob_get_clean() returns the buffer and stops buffering in one call:

php— editable, runs on the server

Nothing reaches the browser until the final echo, which prints HELLO, WORLD!. We captured the text, transformed it, and only then sent it out. This is exactly how a tiny template function works:

<?php

function renderTemplate(string $name): string {
    ob_start();
    echo "Hello, $name!";
    return ob_get_clean();   // contents + stop buffering
}

echo renderTemplate("Ada");

This prints Hello, Ada!. In a real project the buffered block would be a full HTML template with embedded <?= $name ?> tags.

Flush the buffer to the browser

When you only want to delay output (not capture it), use ob_end_flush() to send everything at once:

php— editable, runs on the server

While the buffer is open you can also inspect it with ob_get_length() and ob_get_level():

<?php

ob_start();
echo "buffered text";
echo "\nLevel: " . ob_get_level();   // 1 — one buffer is active
echo "\nLength: " . ob_get_length(); // bytes captured so far
ob_end_flush();

ob_get_level() returns 1 because a single buffer is active; if you call ob_start() again inside it, the level becomes 2 (buffers nest like a stack).

Transform output with a callback

ob_start() accepts a callback that receives the entire buffer and returns the modified version. This is how output minifiers and find-and-replace filters work:

<?php

ob_start(function (string $buffer): string {
    return str_replace("cat", "dog", $buffer);
});

echo "I have a cat.";
ob_end_flush();

The callback runs when the buffer is flushed, so the page prints I have a dog.. The same pattern powers ob_gzhandler, PHP's built-in callback for gzip-compressing output.

Gotchas

  • Always close what you open. Every ob_start() should be matched by a flush or clean call. An unbalanced buffer leaves output stuck in memory and never reaches the user.
  • Buffers nest. Each ob_start() adds a level. ob_get_clean() only closes the innermost one; use ob_get_level() in a loop if you need to unwind several.
  • ob_get_contents() does not stop buffering — only *_clean and *_end_* functions do. Mixing them up is a frequent source of duplicated output.
  • A buffer has a finite size. By default PHP flushes automatically once the buffer reaches output_buffering bytes (php.ini), so don't rely on it to hold an unlimited amount of data.

Conclusion

Output buffering gives you control over when and how your script's output is sent. Use it to capture rendered content as a string, to set headers after generating a page, to discard unwanted output, or to post-process the entire response in one place. Once you understand the start/get/clean/flush cycle, the ob_* family is small and predictable.

Related reading: echo and print, PHP header(), PHP Sessions, and PHP Cookies.

Practice

Practice
Which of the following is true about PHP Output Control?
Which of the following is true about PHP Output Control?
Was this page helpful?