2012-07-04 47 views
10

里面工作,我不知道为什么,但是这个代码为我工作一个月前......也许我升级了PHP,但记不起来了。用PHP 5.2.17和5.3.6Class对象不ob_start回调

为什么不能使用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 

应该是:

This is the awesome Title

回答

10

这是因为输出缓冲器由脚本的终止被隐式地冲洗。

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

您可以通过显式刷新缓冲区关机开始销毁对象之前,通过将以下行某处脚本解决这个问题。

register_shutdown_function('ob_end_flush');

编辑:

我想补充的是,即使这是目前公认的答案,解释“为什么”,这里提供的解决方案并没有解决根本问题问题的原因; global正在使用的事实。

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

通过杰克提供的答案给出了更“最佳实践”的解决方案(使用闭保持变量引用),并应被视为正确的方式,以避免在新的代码库使用global

+2

事实上,为了详细一点:这方面的一个重要组成部分,是_“未引用变量” _被破坏,引用的人都没有。一个很好的例子说明为什么'global'会使代码变得更难,并且适当地传递引用和参数是首选。 – Wrikken

2

ob_start的PHP手册页和a bug report我了解到,自5.2,所有对象均从该名男子页摧毁@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

+0

+1,谢谢你的错误报告参考,我不知道它实际上是改变了行为(除了来自问题作者的评论) – Leigh

+0

@Leigh:NP,在我写了一段代码时遇到了一些麻烦背部。我设法使用闭包来解决它,尽管有些人反对它。顺便提一下:你知道哪一个是_better_,还是仅仅是一个偏好/习惯问题?我不禁想到它与人们没有关系如何关闭工作,更多的是与实际的代码质量相比 –

+1

我同意你的观点,**理解你为什么要做某件事不是坏习惯。使用闭包(恕我直言)不是一种解决方法,它是保留变量引用的正确方法,并避免使用'global'。如何以预期的方式使用语言功能? – Leigh

6

Leigh很好地概述了这个原因。使用关闭将在这种情况下更好地工作:

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

这是因为关闭将参考保持到$f由脚本的最后活着,这样它不会垃圾运行回调函数之前收集的。