PHP flush()与ob_flush()的区别详解


Posted in PHP onJune 03, 2013

buffer ---- flush()
 
buffer是一个内存地址空间,Linux系统默认大小一般为4096(1kb),即一个内存页。主要用于存储速度不同步的设备或者优先级不同的 设备之间传办理数据的区域。通过buffer,可以使进程这间的相互等待变少。这里说一个通俗一点的例子,你打开文本编辑器编辑一个文件的时候,你每输入 一个字符,操作系统并不会立即把这个字符直接写入到磁盘,而是先写入到buffer,当写满了一个buffer的时候,才会把buffer中的数据写入磁 盘,当然当调用内核函数flush()的时候,强制要求把buffer中的脏数据写回磁盘。
同样的道理,当执行echo,print的时候,输出并没有立即通过tcp传给客户端浏览器显示, 而是将数据写入php buffer。php output_buffering机制,意味在tcp buffer之前,建立了一新的队列,数据必须经过该队列。当一个php buffer写满的时候,脚本进程会将php buffer中的输出数据交给系统内核交由tcp传给浏览器显示。所以,数据会依次写到这几个地方echo/pring -> php buffer -> tcp buffer -> browser

php output_buffering --- ob_flush()

默认情况下,php buffer是开启的,而且该buffer默认值是4096,即1kb。你可以通过在php.ini配置文件中找到output_buffering配置.当echo,print等输出用户数据的时候,输出数据都会写入到php output_buffering中,直到output_buffering写满,会将这些数据通过tcp传送给浏览器显示。你也可以通过 ob_start()手动激活php output_buffering机制,使得即便输出超过了1kb数据,也不真的把数据交给tcp传给浏览器,因为ob_start()将php buffer空间设置到了足够大 。只有直到脚本结束,或者调用ob_end_flush函数,才会把数据发送给客户端浏览器。

这两个函数的使用怕是很多人最迷惑的一个问题,手册上对两个函数的解释也语焉不详,没有明确的指出它们的区别,似乎二者的功能都是刷新输出缓存。但在我们文章一开始的代码中如果讲fush()替换成ob_flush(),程序就再不能正确执行了。显然,它们是有区别的,否则也手册中直接说明其中一个是另外一个函数的别名即可了,没必要分别说明。那么它们的区别到底是什么呢?

在没有开启缓存时,脚本输出的内容都在服务器端处于等待输出的状态 ,flush()可以将等待输出的内容立即发送到客户端。

开启缓存后,脚本输出的内容存入了输出缓存中 ,这时没有处于等待输出状态的内容,你直接使用flush()不会向客户端发出任何内容。而 ob_flush()的作用就是将本来存在输出缓存中的内容取出来,设置为等待输出状态,但不会直接发送到客户端 ,这时你就需要先使用 ob_flush()再使用flush(),客户端才能立即获得脚本的输出。

一. flush和ob_flush的正确顺序,正确应是,先ob_flush再flush,如下:
ob_flush();
flush();
如果Web服务器的操作系统是windows系统,那顺序颠倒或者不使用ob_flush()也不会出现问题。[有待求证 ] 但是在Linux系统上就无法刷新输出缓冲。

output buffering函数
1.bool ob_start ([ callback $output_callback [, int $chunk_size [, bool $erase ]]] )
激活output_buffering机制。一旦激活,脚本输出不再直接出给浏览器,而是先暂时写入php buffer内存区域。
php默认开启output_buffering机制,只不过,通过调用ob_start()函数据output_buffering值扩展到足够 大 。也可以指定$chunk_size来指定output_buffering的值。$chunk_size默认值是0,表示直到脚本运行结束,php buffer中的数据才会发送到浏览器。如果你设置了$chunk_size的大小 ,则表示只要buffer中数据长度达到了该值,就会将buffer中 的数据发送给浏览器。
当然,你可以通过指定$ouput_callback,来处理buffer中的数据。比如函数ob_gzhandler,将buffer中的数据压缩后再传送给浏览器。
第三个参数:是否擦除缓存,可选,默认是true,如果设置为false,则在脚本执行结束前,缓存都不会被清除。
2.ob_get_contents
获取一份php buffer中的数据拷贝。值得注意的是,你应该在ob_end_clean()函数调用前调用该函数,否则ob_get_contents()返回一个空字符中。

可以使用ob_get_contents()以字符串形式获取服务端缓存的数据,
使用ob_end_flush()则会输出被缓存起来的数据,并关闭缓存。
而使用ob_end_clean()则会静默的清除服务端缓存的数据,而不会有任何数据或其他行为。
服务端的缓存是堆叠起来的,也就是说你在开启了ob_start()后,关闭之前,在其内部还 可以开启另外一个缓存ob_start()。

不过你也要务必保证关闭缓存的操作和开启缓存的操作数量一样多。
ob_start() 可以指定一个回调函数来处理缓存数据,如果一个ob_start()内部嵌套了另一个ob_start(),我们假定,外层的ob_start(),编号是A,内层的ob_start()编号是B,它们各自制定了一个回调函数分别是functionA和functionB,那么在缓存B中的数据输出时,它会先辈funcitonB回调函数处理,再交给外层的functionA回调函数处理,之后才能输出到客户端。

另外,手册说,对于某些web服务器,比如apache,在使用回调函数有可能会改变程序当前的工作目录,解决方法是在回调函数中自行手动把工作目录修改回来,用chdir函数,这点似乎不常遇到,遇到的时候记得去查手册吧。

3.ob_end_flush与ob_end_clean
这二个函数有点相似,都会关闭ouptu_buffering机制。但不同的是,ob_end_flush只是把php buffer中的数据冲(flush/send)到客户端浏览器,而ob_clean_clean将php bufeer中的数据清空(erase),但不发送给客户端浏览器。

ob_end_flush调用之前 ,php buffer中的数据依然存在,ob_get_contents()依然可以获取php buffer中的数据拷贝。

而ob_end_flush()调用之后 ob_get_contents()取到的是空字符串,同时浏览器也接收不到输出,即没有任何输出。

可以使用ob_get_contents()以字符串形式获取服务端缓存的数据,使用ob_end_flush()则会输出被缓存起来的数据,并关闭缓存。
而使用ob_end_clean()则会静默的清除服务端缓存的数据,而不会有任何数据或其他行为。
服务端的缓存是堆叠起来的,也就是说你在开启了ob_start()后,关闭之前,在其内部还可以开启另外一个缓存ob_start()。不过你也要务必保证关闭缓存的操作和开启缓存的操作数量一样多。
ob_start() 可以指定一个回调函数来处理缓存数据,如果一个ob_start()内部嵌套了另一个ob_start(),我们假定,外层的ob_start(),编号是A,内层的ob_start()编号是B,它们各自制定了一个回调函数分别是functionA和functionB,那么在缓存B中的数据输出时,它会先辈funcitonB回调函数处理,再交给外层的functionA回调函数处理,之后才能输出到客户端。

另外,手册说,对于某些web服务器,比如apache,在使用回调函数有可能会改变程序当前的工作目录,解决方法是在回调函数中自行手动把工作目录修改回来,用chdir函数,这点似乎不常遇到,遇到的时候记得去查手册吧。

PHP 相关文章推荐
PHP 递归效率分析
Nov 24 PHP
Ajax+PHP 边学边练之四 表单
Nov 27 PHP
php 8小时时间差的解决方法小结
Dec 22 PHP
简单的PHP缓存设计实现代码
Sep 30 PHP
PHP下使用CURL方式POST数据至API接口的代码
Feb 14 PHP
深入密码加salt原理的分析
Jun 06 PHP
php Xdebug的安装与使用详解
Jun 20 PHP
Symfony核心类概述
Mar 17 PHP
yii2.0实现pathinfo的形式访问的配置方法
Apr 06 PHP
php性能分析之php-fpm慢执行日志slow log用法浅析
Oct 17 PHP
PHP的mysqli_sqlstate()函数讲解
Jan 23 PHP
php计数排序算法的实现代码(附四个实例代码)
Mar 31 PHP
PHP导出EXCEL快速开发指南--PHPEXCEL的使用详解
Jun 03 #PHP
PHP Cookie的使用教程详解
Jun 03 #PHP
PHP register_shutdown_function函数的深入解析
Jun 03 #PHP
深入PHP与浏览器缓存的分析
Jun 03 #PHP
PHP判断图片格式的七种方法小结
Jun 03 #PHP
基于session_unset与session_destroy的区别详解
Jun 03 #PHP
PHP批量采集下载美女图片的实现代码
Jun 03 #PHP
You might like
YB217、YB235、YB400浅听
2021/03/02 无线电
用php写的serv-u的web申请账号的程序
2006/10/09 PHP
PHP中10个不常见却非常有用的函数
2010/03/21 PHP
php 大数据量及海量数据处理算法总结
2011/05/07 PHP
一致性哈希算法以及其PHP实现详细解析
2013/08/24 PHP
ThinkPHP做文字水印时提示call an undefined function exif_imagetype()解决方法
2014/10/30 PHP
php调用shell的方法
2014/11/05 PHP
PHP中的Trait 特性及作用
2016/04/03 PHP
PHP 闭包详解及实例代码
2016/09/28 PHP
Zend Framework路由器用法实例详解
2016/12/11 PHP
php常用字符串长度函数strlen()与mb_strlen()用法实例分析
2019/06/25 PHP
ThinkPHP5.1验证码功能实现的示例代码
2020/06/08 PHP
document.documentElement && document.documentElement.scrollTop
2007/12/01 Javascript
js菜单点击显示或隐藏效果的简单实例
2014/01/13 Javascript
js过滤HTML标签完整实例
2015/11/26 Javascript
javascript日期格式化方法小结
2015/12/17 Javascript
剖析Node.js异步编程中的回调与代码设计模式
2016/02/16 Javascript
javascript实现标签切换代码示例
2016/05/22 Javascript
jQGrid动态填充select下拉框的选项值(动态填充)
2016/11/28 Javascript
详解webpack4多入口、多页面项目构建案例
2018/05/25 Javascript
用vue快速开发app的脚手架工具
2018/06/11 Javascript
vue+Vue Router多级侧导航切换路由(页面)的实现代码
2018/12/20 Javascript
vuex 动态注册方法 registerModule的实现
2019/07/03 Javascript
Vue搭建后台系统需要注意的问题
2019/11/08 Javascript
Nodejs + sequelize 实现增删改查操作
2020/11/07 NodeJs
python中文乱码的解决方法
2013/11/04 Python
Python中的异常处理相关语句基础学习笔记
2016/07/11 Python
Pytorch中的VGG实现修改最后一层FC
2020/01/15 Python
一道SQL存储过程面试题
2016/10/07 面试题
青年志愿者先进事迹
2014/05/06 职场文书
工地门卫岗位职责范本
2014/07/01 职场文书
党校个人总结
2015/03/04 职场文书
春节随笔
2015/08/15 职场文书
MySQL中日期型单行函数代码详解
2021/06/21 MySQL
JS setTimeout与setInterval的区别
2022/04/20 Javascript
MySQL中TIMESTAMP类型返回日期时间数据中带有T的解决
2022/12/24 MySQL