类对象在ob_start回调中不起作用

时间:2012-07-04 15:41:08

标签: php

我不知道为什么,但这个代码一个月前对我有用......也许我升级了php但不记得了。尝试使用PHP 5.2.17和5.3.6

为什么不能在ob_start函数的回调中使用类对象?

<?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###

输出是:

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

应该是:

  

这是很棒的标题

3 个答案:

答案 0 :(得分:10)

这是因为脚本终止会隐式刷新输出缓冲区。

此时PHP已经销毁了未引用的变量,因此在执行回调函数时,全局范围内不存在变量$f

您可以通过在关闭开始销毁对象之前显式刷新缓冲区来解决此问题,方法是将以下行放在脚本中的某处。

register_shutdown_function('ob_end_flush');

修改

我想补充一点,尽管这是目前接受的解释“why”的答案,但此处提供的解决方案并未解决问题的根本原因; global正在使用的事实。

很多人会告诉你global是邪恶的,没有给出理由。在这里你可以看到其中一个原因。

杰克提供的答案提供了更多“最佳实践”解决方案(使用闭包来维护变量引用),应该被视为避免使用global的正确方法新的代码库。

答案 1 :(得分:6)

Leigh概述了这个原因。在这种情况下,使用闭包会更好:

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

这是因为闭包将在脚本结束时保持对$f的引用活动,以便在运行回调函数之前不会收集垃圾。

答案 2 :(得分:2)

ob_start的php手册页和a bug report我了解到,自5.2以来,所有对象都被销毁了@ob_start

  

此功能的行为已在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";
        }
    }
?>
  

在旧版本中显示:“debug”。   但是最新的php版本会导致错误:PHP致命错误:调用&gt;上的成员函数test()一个非对象。   这不是一个错误:http://bugs.php.net/bug.php?id=40104

来自手册页