剖析 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读取网页文件内容的实现代码(fopen,curl等)
Jun 23 PHP
php用正则表达式匹配中文实例详解
Nov 06 PHP
PHP读取文件内容后清空文件示例代码
Mar 18 PHP
php中使用getimagesize获取图片、flash等文件的尺寸信息实例
Apr 29 PHP
解决CodeIgniter伪静态失效
Jun 09 PHP
教你如何解密 “ PHP 神盾解密工具 ”
Jun 20 PHP
PHP生成器简单实例
May 13 PHP
PHP Cookie学习笔记
Aug 23 PHP
php array_reverse 以相反的顺序返回数组实例代码
Apr 11 PHP
Yii2中添加全局函数的方法分析
May 04 PHP
php在windows环境下获得cpu内存实时使用率(推荐)
Feb 08 PHP
PHP正则表达式笔记与实例详解
May 09 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
福利彩票幸运号码自动生成器
2006/10/09 PHP
深入PHP nl2br()格式化输出的详解
2013/06/05 PHP
解决Codeigniter不能上传rar和zip压缩包问题
2014/03/07 PHP
PHP生成指定长度随机数最简洁的方法
2014/07/14 PHP
PHP正则获取页面所有图片地址
2016/03/23 PHP
thinkPHP框架RBAC实现原理分析
2019/02/01 PHP
使用自定义setTimeout和setInterval使之可以传递参数和对象参数
2009/04/24 Javascript
原生JS实现拖拽图片效果
2020/08/27 Javascript
JavaScript中创建对象的模式汇总
2016/04/19 Javascript
微信公众平台开发教程(六)获取个性二维码的实例
2016/12/02 Javascript
bootstrap模态框跳转到当前模板页面 框消失了而背景存在问题的解决方法
2020/11/30 Javascript
详解百度百科目录导航树小插件
2017/01/08 Javascript
bootstrap confirmation按钮提示组件使用详解
2017/08/22 Javascript
使用MUI框架模拟手机端的下拉刷新和上拉加载功能
2017/09/04 Javascript
vue 监听某个div垂直滚动条下拉到底部的方法
2018/09/15 Javascript
使用electron制作满屏心特效的示例代码
2018/11/27 Javascript
使用post方法实现json往返传输数据的方法
2019/03/30 Javascript
「中高级前端面试」JavaScript手写代码无敌秘籍(推荐)
2019/04/08 Javascript
ElementUI多个子组件表单的校验管理实现
2019/11/07 Javascript
在Vue中使用Select选择器拼接label的操作
2020/10/22 Javascript
下载糗事百科的内容_python版
2008/12/07 Python
python实现的简单窗口倒计时界面实例
2015/05/05 Python
python3.5使用tkinter制作记事本
2016/06/20 Python
Python实现简单http服务器
2018/04/12 Python
PyQt5内嵌浏览器注入JavaScript脚本实现自动化操作的代码实例
2019/02/13 Python
Python pytesseract验证码识别库用法解析
2020/06/29 Python
Belle Maison倍美丛官网:日本千趣会旗下邮购网站
2016/07/22 全球购物
域名注册、建站工具、网页主机、SSL证书:Dynadot
2017/01/06 全球购物
Perfume’s Club德国官网:在线购买香水
2019/04/08 全球购物
土耳其玩具商店:Toyzz Shop
2019/08/02 全球购物
Aurora London官网:奢华、负担得起的皮革手袋
2020/08/01 全球购物
祖国在我心中演讲稿600字
2014/09/23 职场文书
个人求职自荐信范文
2015/03/06 职场文书
离婚起诉书范本
2015/05/18 职场文书
2015入党自传格式范文
2015/06/26 职场文书
MySQL事务的隔离级别详情
2022/07/15 MySQL