剖析 PHP 中的输出缓冲


Posted in PHP onDecember 21, 2006

我们先来看一段代码:

    〈?php
    for ($i=10; $i〉0; $i--)
    {
     echo $i;
     flush();
     sleep(1);
    }
    ?〉

    按照php手册里的说法,该函数将当前为止程序的所有输出发送到用户的浏览器。

    上面的这段代码,应该隔一秒钟输出一次$i。但是实际中却不一定是这样。有可能是等了10秒钟后,所有的输出同时呈现出来。

    好,我们来改一下这段代码,改成

    〈?php
    ob_end_clean();//修改部分
    for ($i=10; $i〉0; $i--)
    {
     echo $i;
     flush();
     sleep(1);
    }
    ?〉
    嘿,加了这一句ob_end_clean();,居然就OK了。实际上,我们把ob_end_clean()换成ob_end_flush()也一样OK。

    我再来改一改。

    〈?php
    for ($i=10; $i〉0; $i--)
    {
     echo $i;
     ob_flush();//修改部分
     flush();
     sleep(1);
    }
    ?〉
    运行一下,是不是发现$i也隔一秒输出一次了?这是为什么呢?
    别急,我们来看看php.ini。

    打开php.ini,搜索output_buffering,我们会看到类似这样的设置 output_buffering = 4096。正如它的名字output_buffering一样,这个设置的作用就是把输出缓冲一下,缓冲大小为4096bytes.

    在我们的第一段代码里,之所以没有按预期的输出,正是因为这个output_buffering把那些输出都缓冲了。没达到4096bytes或者脚本结束,输出是不会被发送出去的。

    而第二段代码中的ob_end_clean()和ob_end_flush()的作用,就是终止缓冲。这样就不用等到有4096bytes的缓冲之后才被发送出去了。

    第三段代码中,用了一句ob_flush(),它的作用就是把缓冲的数据发送出去,但是并不会终止缓冲,所以它必须在每次flush()前使用。

    如果不想使用ob_end_clean(),ob_end_flush()和ob_flush(),我们就必须把php.ini里的output_buffering设得足够小,例如设为0。需要注意的是,如果你打算在脚本中使用ini_set(”output_buffering”,”0″)来设置,那么请停下来吧,这种方法是不行的。因为在脚本一开始的时候,缓冲设置就已经被载入,然后缓冲就开始了。

    可能你会问了,既然ob_flush()是把缓冲的数据发送出去,那么为什么还需要用flush()???直接用下面这段代码不行吗??

    〈?php
    for ($i=10; $i〉0; $i--)
    {
     echo $i;
     ob_flush();
     sleep(1);
    }
    ?〉
    请注意ob_flush()和flush()的区别。前者是把数据从PHP的缓冲中释放出来,后者是把不在缓冲中的或者说是被释放出来的数据发送到浏览器。所以当缓冲存在的时候,我们必须ob_flush()和flush()同时使用。

    那是不是flush()在这里就是不可缺少的呢?不是的,我们还有另外一种方法,使得当有数据输出的时候,马上被发送到浏览器。下面这两段代码就是不需要使用flush()了。(当你把output_buffering设为0的时候,连ob_flush()和ob_end_clean()都不需要了)

    〈?php
    ob_implicit_flush(true);
    for ($i=10; $i〉0; $i--)
    {
     echo $i;
     ob_flush();
     sleep(1);
    }
    ?〉
    〈?php
    ob_end_clean();
    ob_implicit_flush(true);
    for ($i=10; $i〉0; $i--)
    {
     echo $i;
     sleep(1);
    }
    ?〉
    请注意看上面的ob_implicit_flush(true),这个函数强制每当有输出的时候,即刻把输出发送到浏览器。这样就不需要每次输出(echo)后,都用flush()来发送到浏览器了。

    以上所诉可能在某些浏览器中不成立。因为浏览器也有自己的规则。我是用Firefox1.5,IE6,opera8.5来测试的。其中opera就不能正常输出,因为它有一个规则,就是不遇到一个HTML标签,就绝对不输出,除非到脚本结束。而FireFox和IE还算比较正常的。

    最后附上一段非常有趣的代码,作者为PuTTYshell。在一个脚本周期里,每次输出,都会把前一次的输出覆盖掉。
    以下代码只在firefox下可用,其他浏览器并不支持multipart/x-mixed-replace的Content-Type.

    〈?php
      header('Content-type: multipart/x-mixed-replace;boundary=endofsection');
      print “\n--endofsection\n“;

      $pmt = array(“-“, “\\“, “|“, “/“ );
      for( $i = 0; $i 〈10; $i ++ ){
         sleep(1);
         print “Content-type: text/plain\n\n“;
         print “Part $i\t“.$pmt[$i % 4];
         print “--endofsection\n“;
         ob_flush();
         flush();
      }
      print “Content-type: text/plain\n\n“;
      print “The end\n“;
      print “--endofsection--\n“;
    ?〉 

PHP 相关文章推荐
PHP发明人谈MVC和网站设计架构 貌似他不支持php用mvc
Jun 04 PHP
利用yahoo汇率接口实现实时汇率转换示例 汇率转换器
Jan 14 PHP
php获取淘宝分类id示例
Jan 16 PHP
PHP实现单例模式最安全的做法
Jun 13 PHP
php实现批量压缩图片文件大小的脚本
Jul 04 PHP
教你如何开启shopnc b2b2c 伪静态
Oct 21 PHP
php读取远程gzip压缩网页的方法
Dec 29 PHP
WordPress中获取指定分类及其子分类下的文章数目
Dec 31 PHP
Symfony2之session与cookie用法小结
Mar 18 PHP
PHP基于XMLWriter操作xml的方法分析
Jul 17 PHP
php 删除指定文件夹的实例讲解
Jul 25 PHP
浅析php如何实现爬取数据原理
Sep 27 PHP
PHP 的几个配置文件函数
Dec 21 #PHP
使用 MySQL 开始 PHP 会话
Dec 21 #PHP
PHP 编程请选择正确的文本编辑软件
Dec 21 #PHP
PHP 模板高级篇总结
Dec 21 #PHP
PHP函数utf8转gb2312编码
Dec 21 #PHP
小偷PHP+Html+缓存
Dec 20 #PHP
PR值查询 | PageRank 查询
Dec 20 #PHP
You might like
用PHP生成自己的LOG文件
2006/10/09 PHP
Admin generator, filters and I18n
2011/10/06 PHP
支持中文的php加密解密类代码
2011/11/27 PHP
Laravel使用PHPQRCODE实现生成带有LOGO的二维码图片功能示例
2017/07/07 PHP
Laravel关联模型中过滤结果为空的结果集(has和with区别)
2018/10/18 PHP
PHP的mysqli_ssl_set()函数讲解
2019/01/23 PHP
通过JavaScript使Div居中并随网页大小改变而改变
2013/06/24 Javascript
jquery ui dialog实现弹窗特效的思路及代码
2013/08/03 Javascript
js倒计时小程序
2013/11/05 Javascript
使用Javascript实现选择下拉菜单互移并排序
2016/02/23 Javascript
Node.js中npm常用命令大全
2016/06/09 Javascript
javascript 数据存储的常用函数总结
2017/06/01 Javascript
js全屏事件fullscreenchange 实现全屏、退出全屏操作
2019/09/17 Javascript
JavaScript监听键盘事件代码实现
2020/06/03 Javascript
[02:06]2018完美世界全国高校联赛秋季赛开始报名(附彩蛋)
2018/09/03 DOTA
[01:16:50]DOTA2-DPC中国联赛 正赛 Phoenix vs CDEC BO3 第一场 3月7日
2021/03/11 DOTA
python 提取tuple类型值中json格式的key值方法
2018/12/31 Python
python utc datetime转换为时间戳的方法
2019/01/15 Python
Python匿名函数及应用示例
2019/04/09 Python
python实现弹跳小球
2019/05/13 Python
使用Flask-Cache缓存实现给Flask提速的方法详解
2019/06/11 Python
Python turtle绘画象棋棋盘
2019/08/21 Python
利用rest framework搭建Django API过程解析
2019/08/31 Python
OpenCV模板匹配matchTemplate的实现
2019/10/18 Python
python实现12306登录并保存cookie的方法示例
2019/12/17 Python
python GUI库图形界面开发之PyQt5简单绘图板实例与代码分析
2020/03/08 Python
pytorch中的weight-initilzation用法
2020/06/24 Python
英国图书音像网站:Hive.co.uk(图书、电子书、DVD、蓝光、音乐CD等)
2017/10/16 全球购物
优秀学生自我鉴定范例
2013/12/18 职场文书
学生会主席竞聘书
2014/03/31 职场文书
司机岗位职责说明书
2014/07/29 职场文书
国际贸易实训报告
2014/11/05 职场文书
2014年工程师工作总结
2014/11/25 职场文书
2015年党风廉政承诺书
2015/01/22 职场文书
电工生产实习心得体会
2016/01/22 职场文书
工作转正自我鉴定范文
2019/06/21 职场文书