Php 与只处理ob_get_clean()的结果相比,将回调传递给ob_start有什么好处?

Php 与只处理ob_get_clean()的结果相比,将回调传递给ob_start有什么好处?,php,performance,coding-style,output-buffering,Php,Performance,Coding Style,Output Buffering,我想知道使用这个是否有什么真正的好处 function getSomeContent() { ob_start(function($content) { // ... modify content ... return $content; } // ... output stuff ... return ob_get_clean(); } …与此相反 function getSomeContent() { ob_start

我想知道使用这个是否有什么真正的好处

function getSomeContent() {
    ob_start(function($content) {
        // ... modify content ...
        return $content;
    }
    // ... output stuff ...
    return ob_get_clean();
}
…与此相反

function getSomeContent() {
    ob_start();
    // ... output stuff ...
    $result = ob_get_clean();
    // ... modify content ...
    return $result;
}

假设“输出内容”和“修改内容”部分在每种情况下都是相同的。关键的一点是,“修改内容”已经改变了它的位置,在第一种情况下是在回调中,在第二种情况下是“内联”的

是否存在一个优于另一个的性能优势?例如,当第一个表单仅使用一个时,第二个表单是否制作了两个缓冲区内容副本?或者这纯粹是一个编码风格的决定?为什么你会选择一种形式而不是另一种


我可以看出在范围访问方面存在差异,因为在第二个示例的“modify content”部分中可以使用封闭范围中的任何变量,在第一个示例中,它们必须通过
use
子句“传入”。事实上,这正是我通常选择第二种形式的原因。

现在您的代码很清楚了是的,在第一个示例中,您给出了一个案例,其中您使用了两次
$result
(这不是一个好主意)

我的主要想法是:只有在当前范围内不需要使用
$result
时,才使用回调调用
ob\u start
。您的第一个示例是:

ob_start(function($content) {
    // ... modify content ...
    return $content;
}
// ... output stuff ...
ob_end_clean();

在这种情况下,带有
$result
的作业在一个新的作用域中进行,这可以使您的代码更干净(例如:您调用
ob_start(array($this,'method');
),并且您不需要
取消设置
您的
$result
就可以在作业结束时将其从主作用域中释放出来(我假定您正在做其他事情).

只是想澄清一下尼索的正确答案

我的两个代码示例实际上不会产生相同的结果。事实上,将回调与
ob\u get\u clean()
结合使用是完全无用的

这是因为回调是在清理或刷新缓冲区时应用的

但是
ob\u get\u clean()
首先检索内容,然后清理缓冲区。这意味着返回的内容不是回调返回的结果,而是传递给回调的输入

我写了这两个简单的脚本来演示

此选项使用了
ob\u get\u clean()
,但不能产生正确的结果:

// Tests the use of callbacks with ob_get_clean().
class TestWithGetClean {
    // This variable is set when obcallback is called.
    public $foo = null;

    // The output buffer callback.
    public function obcallback($value) { 
        $this->foo = 'set';
        return $value . '(modified)'; 
    }

    // Main method.
    public function run() {
        ob_start(array($this, 'obcallback'));
        echo 'this is the output', PHP_EOL;
        return ob_get_clean();
    }
}

// Run the test with ob_get_clean().
$t = new TestWithGetClean();
echo $t->run(); // This method returns a value in this test. (But not the correct value!)
echo $t->foo, PHP_EOL;
运行此命令的输出为:

这是输出

设置

文本
'(已修改)
不会出现在任何地方。但是请注意,设置了实例变量
$foo
,因此肯定会调用回调,但是输出并不像我最初期望的那样

与使用
ob\u end\u flush()

此操作将生成以下输出:

这是输出

(修改)

设置


但是,这当然没有那么有用,因为输出直接发送到客户机,所以我们无法进一步操作结果。(例如,将文本包装在Symfony HttpFoundation组件请求对象中)。

在第一种情况下,不需要执行
$result=ob_get_clean(),您将执行
ob_end_clean()(也在清理之前调用回调)。否则第二个案子就是你的了。如果你想以这种方式使用第一种情况(修改2倍的结果),你只需给你的应用程序增加复杂性。谢谢@Ninsuo,但我认为你可能没有正确理解我的代码示例(我的问题不够清楚),所以我添加了更多的上下文,让它们成为具有相同签名的方法调用。第一种情况不是两次修改结果,我不明白你的意思,你能澄清一下情况吗?当然,我想使用
ob\u get\u clean()
而不是
ob\u end\u clean()
,因为这只会丢弃我想要保留的缓冲区的内容。我问的是如何在
ob_start()
中使用回调,而不是“内联”处理结果。虽然我认为所有这些都只是编码风格的问题(Ninsuo正确地指出回调风格可以让代码更简洁),您应该重新评估是否真的有必要使用输出缓冲来捕获输出。你在
ob\u start
ob\u get\u clean
之间做什么?首先,你不能将输出附加到一个变量吗?@akirk老实说,这个问题主要是理论上的,我倾向于同意,但是我发现将视图脚本包装在
ob\u start()
ob\u get\u clean()
(没有回调!)中非常有用,然后视图脚本可以使用标准输出函数(
echo
etc),我以后仍然可以处理输出。至于回调,我很难确定我是否会使用它们。谢谢@Ninsuo。如果我理解正确,你是说如果你直接输出缓冲区内容,然后将回调传递给
ob_start()
可以更干净。但如果你对内容做了其他事情,那么使用回调就没有什么真正的好处。这是有道理的。我喜欢使用方法引用作为回调的想法,除了它会破坏我的OO方面,因为该方法不应该是真正公开的,从技术上讲,它是一个实现细节应该保密。(可以使用
ReflectionMethod::setAccessible
也许)。我唯一不明白的是为什么调用
ob\u end\u clean()
,它只会丢弃缓冲区内容。我确定这是
echo ob\u end\u clean()
还是我仍然缺少什么?我正在使用
ob\u end\u clean()
因为当你清理缓冲区时,你的回调仍然被调用。因此,如果你使用回调,我假设你不需要在你的主作用域中得到结果,所以你不需要返回你的
$result
。如果你需要
回显ob_get_clean();
// Tests the use of callbacks with ob_end_flush().
class TestWithEndFlush {
    // This variable is set when obcallback is called.
    public $foo = null;
    
    // The output buffer callback.
    public function obcallback($value) { 
        $this->foo = 'set';
        return $value . '(modified)' . PHP_EOL; 
    }

    // Main method.
    public function run() {
        ob_start(array($this, 'obcallback'));
        echo 'this is the output', PHP_EOL;
        ob_end_flush();
    }
}

// Run the test with ob_end_flush().
$t2 = new TestWithEndFlush();
$t2->run(); // This method produces output in this test.
echo $t2->foo, PHP_EOL;