MilMike
MilMike

Reputation: 12831

Class object not working inside ob_start callback

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

Upvotes: 12

Views: 2556

Answers (3)

lll
lll

Reputation: 12889

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.

Upvotes: 11

Ja͢ck
Ja͢ck

Reputation: 173562

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.

Upvotes: 7

Elias Van Ootegem
Elias Van Ootegem

Reputation: 76395

From the php manual page of ob_start, and a bug report I learned that, since 5.2, all objects are destroyed @ob_start

This function's behaviour has been changed in php 5.2.0:

<?
    global $AP;
    $AP = new ap;
    ob_start("ob_end");
    function ob_end()
    {
        global $AP;
        $r = $AP->test();
        return $r;
    }
    class ap
    {
        function test()
        {
            return "debug";
        }
    }
?>

In older versions it shows: "debug". But latest php version causes error: PHP Fatal error: Call to a member function test() on > a non-object. And this is not a bug: http://bugs.php.net/bug.php?id=40104

from the man pages

Upvotes: 2

Related Questions