10

理由はわかりませんが、このコードは1か月前に機能しました...おそらく、phpをアップグレードしましたが、思い出せません。PHP5.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多くの人は、理由を説明せずに、それは悪だと言うでしょう。ここでは、理由の1つを見ることができます。

Jackが提供する回答は、より「ベストプラクティス」の解決策(クロージャを使用して変数参照を維持する)を提供しglobal、新しいコードベースでの使用を回避する適切な方法と見なす必要があります。

于 2012-07-04T15:49:37.263 に答える
6

この理由は、リーによってよく概説されています。この場合、クロージャーを使用するとより適切に機能します。

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で破棄されることがわかりました。

この関数の動作は、php5.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 に答える