【问题标题】:PHP endless while loop confusionPHP 无休止的 while 循环混乱
【发布时间】:2013-03-08 20:34:59
【问题描述】:

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

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

我希望它每秒向浏览器返回“你好”……我错了吗?现在页面似乎挂了。

【问题讨论】:

  • 你的 HTTP 服务器正在缓冲输出
  • 这不是flush()的用途吗?
  • @mootymoots:php 有自己的缓冲区,它可以随时刷新。但是网络服务器也可以进行缓冲,而 php 对此几乎没有控制权。上游也可能有进一步的缓冲(服务器网络堆栈、反向代理系统等),而 php 绝对无法影响它。

标签: php while-loop


【解决方案1】:

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

【讨论】:

  • 这不是flush()的用途吗?
  • 阅读flush文档:php.net/manual/en/function.flush.phpflush“有点”有效,但更多时候不是,不是
  • 不正确,你真的可以逐行输出,但你必须flush()并确保output_buffering被禁用,或者像valentin所说的那样调用ob_flush()
【解决方案2】:

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

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

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

【讨论】:

  • 这不是一个好的答案,因为它不能可靠地工作(如果有的话),正如 herecomments of ob_flush() 所记录的那样。 AJAX 是在所有浏览器中可靠且一致地实现问题的唯一方法。并且无需修改服务器设置。
【解决方案3】:

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

在 Javascript 中,这非常简单。

<script>
    window.setInterval(function(){document.innerHTML += "<br> Hello"}, 1000)
</script>

【讨论】:

  • 只有在管道的其余部分没有缓冲输出时才可以使用,并且浏览器和 Web 服务器几乎总是在显示之前缓冲输出。
  • 更重要的是,在什么样的实际场景中你甚至想要这个功能?
  • 我指的是彗星的例子,他们使用这个:例如:zeitoun.net/articles/comet_and_php/start
  • 在阅读世界场景中是的,但问题是通常没有为它配置 HTTP 服务器。 NodeJS 是处理这类事情的好工具,但它可以用 PHP 来完成。实际上,您可以使用 PHP 为这些事情创建一个简单的服务器,但我会使用 node 来处理交互式内容。
  • 和@snostorm 你是绝对正确的,中间的东西太多了,所以在通常的 PHP 网站中你不需要/想要这个功能。
【解决方案4】:

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

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

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

【讨论】:

  • 不太对。 PHP 可以/将根据需要向客户端发送输出。但仅当脚本完成和/或输出缓冲区被填满时。很可能有一个 php 脚本发送无限数据,并且会很快出现在客户端。
  • 你说的很对,谢谢我修正了我的答案以反映这个评论:)
【解决方案5】:

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

<?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';

【讨论】:

    【解决方案6】:

    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。默认情况下,请参阅configuration variables 将其关闭/打开。

    【讨论】:

      【解决方案7】:

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

      output_buffering = On
      

      output_buffering = 4096 (default setting on most distributions)
      

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

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

      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);
      }
      

      Cya..

      【讨论】:

        【解决方案8】:

        添加到所有其他答案,

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

        【讨论】:

          猜你喜欢
          • 2013-03-18
          • 2021-12-30
          • 1970-01-01
          • 1970-01-01
          • 2017-08-29
          • 2015-02-10
          • 2011-11-29
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多