【问题标题】:PHP: Output buffer callback not altering outputPHP:输出缓冲区回调不改变输出
【发布时间】:2012-09-12 15:59:34
【问题描述】:

我有一个带有回调函数的输出缓冲区。然而,当清理缓冲区时,回调函数被执行,返回的字符串并没有被改变。

我正在使用以下代码:

<?php
ob_start('callback');
print 'some text';
error_log(ob_get_clean());

function callback($content) {
  error_log('callback');
  return $content . ' altered'; 
}

输出:

callback
some text

我想要什么:

callback
some text altered

我错过了什么?我在 CLI 中使用 PHP 5.3.10。

编辑:正在执行回调。

来自 PHP 手册:

该函数将在输出缓冲区被刷新(发送)时调用 或清理(使用 ob_flush()、ob_clean() 或类似函数)或何时 输出缓冲区在请求结束时刷新到浏览器。

【问题讨论】:

  • php 手册是否说这包括 ob_get_clean()?你的实验是一个强有力的论据,可以说它没有。此外,似乎缓冲区正在被修改,但获取的结果不是。

标签: php output-buffering


【解决方案1】:

我不确定这是错误还是功能。看PHP源码发现ob_get_clean的返回值在回调调用之前就填好了。

我看到至少两种解决方法。第一种是自己手动调用输出字符串的回调。我认为这无需举例。

第二个是利用堆栈输出缓冲的可能性。由于刷新成功使用回调,您可以将输出代码包装在额外的输出缓冲区中并获取修改后的内容。

ob_start();

function callback($input) { return $input . " altered"; }
ob_start('callback');
echo "foo";
ob_end_flush();

$content = ob_get_clean();
ob_end_clean();
echo $content . "\n"; // prints "foo altered\n"

如果您好奇,请参阅ob_get_clean (main/output.c) 的源代码。您可以在 PHP 网站上获取源代码。这里有一些提示。

/* {{{ proto bool ob_get_clean(void)
   Get current buffer contents and delete current output buffer */
PHP_FUNCTION(ob_get_clean)
{
    if (zend_parse_parameters_none() == FAILURE) {
        return;
    }

    // THIS CALL FILLS THE RETURN VALUE
    if (php_ob_get_buffer(return_value TSRMLS_CC) == FAILURE) {
        RETURN_FALSE;
    }

    if (!OG(ob_nesting_level)) {
        php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete");
        zval_dtor(return_value);
        RETURN_FALSE;
    }
    if (OG(ob_nesting_level) && !OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) {
        php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer %s", OG(active_ob_buffer).handler_name);
        zval_dtor(return_value);
        RETURN_FALSE;
    }

    // THIS CALL KILLS THE CURRENT BUFFER AND EXECUTES THE CALLBACK
    php_end_ob_buffer(0, 0 TSRMLS_CC);
}
/* }}} */

php_end_ob_buffer 获取 OB 缓冲区的内容并对其应用回调。如果第一个参数为真,它会将内容传递给下一个输出缓冲处理程序。在这种情况下它是假的,所以即使它执行了回调,内容也会丢失。

【讨论】:

    【解决方案2】:

    如果我有一个猜测,它会是这个。

    ob_get_clean() 正在返回缓冲区的结果,THEN 清理它,触发修改内容的回调。

    IE

    “一些文本”从缓冲区中提取出来,并根据“获取”功能的要求准备返回。

    接下来,缓冲区被清理,但在清理之前,根据回调存在时各种 ob 函数的要求,针对内容触发回调。

    结果是缓冲区被返回(按请求)但在之后被修改,因为 get 发生在 clean 之前。

    【讨论】:

      【解决方案3】:

      缓冲区刷新时调用:

      ob_start('callback');
      print 'some text';
      ob_end_flush();
      
      function callback($content) {
        return $content . ' altered'; 
      }
      

      附: 它也适用于 CLI。

      【讨论】:

        【解决方案4】:

        PHP 的 CLI 不使用输出缓冲(或者更具体地说,缓冲与 ob_ 函数无关)。所以你的回调被跳过了。

        编辑:实际上我无法确认 CLI 是否提供标准输出缓冲。我会尝试ob_end_flush()ob_flush()flush()

        【讨论】:

        • 我可以看到添加调试消息时正在执行回调。
        【解决方案5】:

        我删除了 ob_get_clean 并且你的代码确实有效。

        ob_start('callback');
        print 'some text';
        //error_log(ob_get_clean());
        
        $buffer = ob_get_flush();
        
        function callback($content) {
          return $content . ' altered';
        }
        

        我检查了输出,它是一些警告文本。

        为什么你使用 ob_get_clean() 方法?它会清理缓冲区。

        【讨论】:

        • 我没用,第三方用的。还有成千上万的原因。
        【解决方案6】:
        <?php ob_start('callback'); ?>
        
            Foo Bar Baz
        
        <?php
          ob_end_flush();
        
          function callback($content) {
            $find = "Baz";
            $replace_with = "Foo";
            return (
              str_replace($find, $replace_with, $content)
            );
          }
        ?>
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-02-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-07-24
          • 1970-01-01
          相关资源
          最近更新 更多