2

我试图弄清楚为什么这个循环不会向浏览器返回任何内容:

while(1) {
    echo "hello";
    flush();
    sleep(1);
}

我期待它每秒向浏览器返回“你好”......我错了吗?现在页面似乎只是挂起。

4

8 回答 8

3

PHP 仅在执行完成后输出。所以你所做的就是每毫秒生成一个新的 hello,并且由于你从不退出循环,所以你永远看不到输出。

于 2013-03-08T20:37:05.203 回答
2

为了更正我的答案并让您更好地理解,并且对于 AJAX 爱好者......你需要在那里额外冲洗......'ob_'一个:

<?php
while( 1 ):
    echo "hello";
    ob_flush( ); flush();
    sleep( 1 );
endwhile;

这是每个需要知道的人的“诀窍”;)

于 2013-03-22T08:24:53.490 回答
0

Valentin给了你正确的答案(支持他/接受他的答案!),但没有解释原因。这是解释:

输出缓冲

PHP 不会立即输出到浏览器,它会等待有一些内容发送到浏览器(可能以 1024、2048 或 4096 字节的块发送),或者在执行结束时。调用flush()使 PHP 发送数据,但不止一层缓冲。一种是内部缓冲(我刚刚评论过),但您可以添加更多缓冲层。假设这段代码:

<?php
echo "hi";
setcookie('mycookie', 'somevalue');
?>

setcookie()函数向浏览器发送一个 http 标头,但它不能这样做,因为在 HTTP 中,服务器(或客户端,两种方式都相同)必须首先发送所有标头,一个空行,然后是内容。如您所见,您在标头之前输出了一些内容(hi),因此它失败了(因为内部缓冲遵循相同的执行顺序)。

您可以使用 php 函数添加另一层输出缓冲ob_*()。通过ob缓冲它只缓冲内容输出,而不是 HTTP 标头。您可以使用它们来获取直接输出到浏览器的函数的输出,例如var_dump(). 此外,您可以嵌套以下层ob

<?php
// start first level of output buffering
ob_start();
echo "nesting at level ", ob_get_level(), "<br />\n"; // prints level 1
echo "hi<br />";
ob_start();
echo "nesting at level ", ob_get_level(), "<br />\n"; // prints level 2
var_dump($_POST);
$post_dump = ob_get_clean();

// this will print level 1, because ob_get_clean has finished one level.
echo "nesting at level ", ob_get_level(), "<br />\n";

echo "The output of var_dump(\$_POST) is $post_dump<br />\n";

// in spite of being inside a layer of output_buffering, this will work
setcookie('mycookie', 'somevalue');

// flush the current buffer and delete it (will be done automatically at the
// end of the script if not called explicitly)
ob_end_flush();

可能您的 PHP 服务器默认启用了 output_buffering。查看配置变量以默认关闭/打开它。

于 2013-03-22T08:50:53.853 回答
0

好的,卡洛斯批评我,因为我没有解释我的答案,但他的答案是含糊的......用饼干,层...... POST,ob_levels......:OO到很多关于真正问题没有真正意义的信息用户,但我会告诉你为什么你的代码不起作用。因为您在 php.ini 中设置了输出缓冲,例如:

output_buffering = On

或者

output_buffering = 4096 (default setting on most distributions)

这就是为什么你需要额外的'ob_flush()'来摆脱任何垃圾输出..

所以...要使您的代码正常工作,您有两个选择:

1). set output_buffering = 0 or Off (if you have access to the php.ini)
2). ob_flush many times as layers of buffering you have

如果您不知道您有多少层,您可以执行以下操作:

while (@ob_end_clean( ));

并清理你可能拥有的所有垃圾,然后你的代码就可以正常工作了。完整的片段:

<?php
while (@ob_end_clean( ));
while(1) {
    echo "hello";
    flush();
    sleep(1);
}

赛亚..

于 2013-03-22T09:58:26.667 回答
0

在收到整个页面之前,浏览器不会显示任何内容。PHP 无法完成您想要完成的工作。

在 Javascript 中,这非常简单。

<script>
    window.setInterval(function(){document.innerHTML += "<br> Hello"}, 1000)
</script>
于 2013-03-08T20:36:49.170 回答
0

您应该意识到 PHP 是一种脚本语言,因为它仅在完成脚本后才返回输出。编辑:或者在输出缓冲区被填满后,感谢@Marc B。不管我会说为此使用 JS 或者如果你真的需要你的服务器更明智,请使用 AJAX 请求。

也许您应该考虑使用 Javascript?这将允许您每秒添加内容(请记住,JS 在客户端运行,因此您可能不想让您的操作变得如此广泛。)

或者,您可以考虑通过例如 JQuery 使用 AJAX 请求,但这可能超出了这个问题的范围......

于 2013-03-08T20:39:42.080 回答
0

也许回答还不算晚,但是如果您想在这里每秒刷新一次,我给您一个示例:

<?php
echo "Flushing every second ...\n";
flush( );
$seconds = array (0,1,2,3,4,5,6,7,8,9);

foreach ($seconds as $second):
    echo $second . "\n";
    sleep( 1 );
    @ob_flush( ); flush( );
endforeach;
echo 'I flashed 10 second :P';
于 2013-03-22T07:00:51.067 回答
-1

添加到所有其他答案,

要对客户端进行异步服务器推送,您需要使用 WebSockets。这是一个庞大的主题,并没有完全标准化,但肯定有办法做到这一点。如果您有兴趣搜索 PHP Websockets。

于 2013-03-08T20:44:47.730 回答