10

我不知道为什么,但这个代码一个月前对我有用......也许我升级了 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 

应该:

这是很棒的标题

4

3 回答 3

10

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

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

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

register_shutdown_function('ob_end_flush');

编辑:

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

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

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

于 2012-07-04T15:49:37.263 回答
6

Leigh 已经很好地概述了其原因。在这种情况下使用闭包会更好:

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

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

于 2012-07-04T15:53:36.840 回答
2

从 php 手册页ob_start错误报告中我了解到,从 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";
        }
    }
?>

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

从手册页

于 2012-07-04T15:50:33.357 回答