Reputation: 4614
I am wondering if there is any real benefit to using this...
function getSomeContent() {
ob_start(function($content) {
// ... modify content ...
return $content;
}
// ... output stuff ...
return ob_get_clean();
}
...as opposed to this...
function getSomeContent() {
ob_start();
// ... output stuff ...
$result = ob_get_clean();
// ... modify content ...
return $result;
}
...?
Assume the "output stuff" and "modify content" parts are the same in each case. The key point is that the "modify content" has changed its location, being in a callback in the first case, and being "inline" in the second case.
Is there a performance benefit of one over the other? For example, does the second form make two copies of the buffer contents when the first uses only one? Or is it purely a coding style decision? Why would you choose one form over the other?
I can see there are differences in scope access, because any variables in the enclosing scope will be available in the "modify content" part of the second example, where they would have to be "passed in" with a use
clause in the first example. In fact this is exactly why I would normally choose the second form.
Upvotes: 2
Views: 2963
Reputation: 4614
Just to clarify Ninsuo's correct answer a bit.
My two code samples actually do not produce the same result. In fact, using the callback in combination with ob_get_clean()
is completely useless.
This is because the callback is applied when cleaning or flushing the buffer.
However ob_get_clean()
retrieves the contents first, and then cleans the buffer. Which means that the contents returned are not the result returned by the callback, but the input passed to the callback.
I wrote these two simple (and hacky) scripts to demonstrate.
This one uses ob_get_clean()
and does not produce the correct result:
// Tests the use of callbacks with ob_get_clean().
class TestWithGetClean {
// This variable is set when obcallback is called.
public $foo = null;
// The output buffer callback.
public function obcallback($value) {
$this->foo = 'set';
return $value . '(modified)';
}
// Main method.
public function run() {
ob_start(array($this, 'obcallback'));
echo 'this is the output', PHP_EOL;
return ob_get_clean();
}
}
// Run the test with ob_get_clean().
$t = new TestWithGetClean();
echo $t->run(); // This method returns a value in this test. (But not the correct value!)
echo $t->foo, PHP_EOL;
The output from running this is:
this is the output
set
The text '(modified)'
does not appear anywhere. Note however that the instance variable $foo
is set, so the callback is definitely called, however the output is not as I originally expected.
Compare to this one which uses ob_end_flush()
:
// Tests the use of callbacks with ob_end_flush().
class TestWithEndFlush {
// This variable is set when obcallback is called.
public $foo = null;
// The output buffer callback.
public function obcallback($value) {
$this->foo = 'set';
return $value . '(modified)' . PHP_EOL;
}
// Main method.
public function run() {
ob_start(array($this, 'obcallback'));
echo 'this is the output', PHP_EOL;
ob_end_flush();
}
}
// Run the test with ob_end_flush().
$t2 = new TestWithEndFlush();
$t2->run(); // This method produces output in this test.
echo $t2->foo, PHP_EOL;
This one produces the following output:
this is the output
(modified)
set
However, this is of course not as useful because the output goes directly to the client, so we cannot further manipulate the result. (For example, wrapping the text in a Symfony HttpFoundation Component Request object).
Upvotes: 1
Reputation: 36954
Now your code is clear yes, in your first samples you given a case where you used $result
twice (that wasn't a good idea).
My main idea is : you call ob_start
with a callback only if you do not need to use your $result
in your current scope. Your first example becomes :
ob_start(function($content) {
// ... modify content ...
return $content;
}
// ... output stuff ...
ob_end_clean();
In this case, the job with $result
is made in a new scope and this can make your code cleaner (example: you call ob_start(array($this, 'method'));
), and you don't need to unset
your $result
to free it from your main scope at the end of your job (I assume you're doing something else of course).
Upvotes: 2