Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Class object not working inside ob_start callback

Tags:

php

I don't know why, but this code worked for me a month ago... maybe I upgraded the php but can't remember. Tried this with PHP 5.2.17 and 5.3.6

Why is it not possible to use a class object inside the callback of a ob_start function?

<?php
$f=new stdClass();
$f->title="awesome Title";

function callback($buffer) 
{
    global $f;
    $buffer=str_replace("###TITLE###", $f->title, $buffer);
    return $buffer;
}
ob_start("callback");
?>

This is the ###TITLE###

Output is:

PHP Notice:  Trying to get property of non-object in /Users/qxxx/Sites/test/test.php on line 8
This is the 

should be:

This is the awesome Title

like image 839
MilMike Avatar asked Jul 04 '12 15:07

MilMike


People also ask

What does Ob_start () mean?

Definition and Usage The ob_start() function creates an output buffer. A callback function can be passed in to do processing on the contents of the buffer before it gets flushed from the buffer. Flags can be used to permit or restrict what the buffer is able to do.

When to use ob_ start?

In order to enable the Output Buffering one must use the ob_start() function before any echoing any HTML content in a script.

What is ob_ start() in PHP w3schools?

Using ob_start allows you to keep the content in a server-side buffer until you are ready to display it. This is commonly used to so that pages can send headers 'after' they've 'sent' some content already (ie, deciding to redirect half way through rendering a page).


2 Answers

This is because the output buffer is being implicitly flushed by the termination of the script.

At this point PHP has already destroyed unreferenced variables, so when it comes to execute your callback function, the variable $f does not exist in the global scope.

You can solve this by explicitly flushing the buffer before shutdown starts destroying objects, by placing the following line somewhere in your script.

register_shutdown_function('ob_end_flush');

Edit:

I'd like to add that even though this is currently the accepted answer that explains the "why", the solution provided here does not address the root cause of the issue; the fact that global is being used.

Many people will tell you that global is evil, without giving a reason why. Here you can see one of the reasons.

The answer provided by Jack gives a more "best practice" solution (using closures to maintain the variable reference), and should be considered as the proper way to avoid using global in new codebases.

like image 63
Leigh Avatar answered Oct 12 '22 23:10

Leigh


The reason for this has been outlined well by Leigh. Using a closure would work better in this case:

ob_start(function($b) use ($f) {
        return str_replace('###TITLE###', $f->title, $b);
});

This is because the closure will keep the reference to $f alive by the end of the script so that it won't get garbage collected before running the callback function.

like image 44
Ja͢ck Avatar answered Oct 12 '22 22:10

Ja͢ck