buffer是一个内存地址空间,linux系统默认大小一般为4096(4kb)。主要用于存储速度不同步的设备或优先级不同的设备之间传递数据的区域。
通过buffer可以使进程之间的相互等待变少。
例如,当你打开一个文本编辑器,输入一个字符时,系统并不会立即写入磁盘。而是存储在buffer中,当写满一个buffer时,才会把buffer的内容写入磁盘。
当然也可以使用flush强制将buffer的数据写入磁盘。
在php中,例如 echo,print,输出并不会立即通过tcp传递给浏览器输出。而是将数据写入php buffer。当一个php buffer写满,才会通过tcp传递给浏览器。
echo /print -> php output_buffer -> tcp buffer -> browser
php output_buffering
默认情况下,php buffer是开启的,默认值是4096(4kb)。可以在php.ini中找到output_buffering 配置。知道buffer写满,才会发送到浏览器。
也可以设置ob_start(),这样即使超过默认值(4kb)也不会立即发送到浏览器,只到脚本运行完成,或者调用了ob_end_flush方法,才会输出到浏览器。
1.output_buffering=4096,输出较少的数据(少于一个buffer)
';
sleep(2);
}
?>
运行结果:等所有脚本全部运行完成后,才输出,因为数据未满一个buffer的大小。
2.output_buffering=4096,输出较少的数据(少于一个buffer),关闭output_buffering,修改php.ini的output_buffering=0
'; // 当接受到的256(甚至更多)个字节以后才开始显示该页面,所以必须发送一些额外的空格来让这些浏览器显示页面内容。
flush();
sleep(1);
}
?>
运行结果:因为禁用了php buffering,不需要等到脚本运行完毕就可以输出,数据没有在php buffer停留,可以看到断断续续间歇性输出。echo -> tcp buffer ->browser
3.当output_buffering=4096,输出较大数据(大于一个buffer),不使用ob_start()
';
sleep(1);
}
?>
运行结果:f.txt为一个大于4kb的文件,因为大于buffer默认值,buffer空间不够用,每当满一个buffer就会输出,所以可以看到间歇性输出。
4.当output_buffering=4096,输出较大数据(大于一个buffer),使用ob_start()
';
sleep(1);
}
?>
运行结果:因为使用了ob_start(),会为buffer设置足够大的空间,因此会保存到脚本执行完毕后才会输出。
output_buffering 方法
1.ob_start
激活output_buffering机制,一旦激活,脚本不再直接输出到浏览器,而是暂时写入php buffering区域。直到脚本运行完毕后,才发送。
2.ob_get_contents
获取php buffering中的数据,注意:要在ob_end_clean()前调用,否则只会得到空字符。
3.ob_end_flush 和 ob_end_clean
ob_end_flush 会输出php buffering 中的数据,但不会清空。
ob_end_clean 不会输出,只会清空php buffering中的数据。
注意:
ob_flush/flush在手册中的描述, 都是刷新输出缓冲区, 并且还需要配套使用, 所以会导致很多人迷惑…
其实, 他们俩的操作对象不同, 有些情况下, flush根本不做什么事情..
ob_*系列函数, 是操作PHP本身的输出缓冲区.
所以, ob_flush是刷新PHP自身的缓冲区.
而flush, 严格来讲, 这个只有在PHP做为apache的Module(handler或者filter)安装的时候, 才有实际作用. 它是刷新WebServer(可以认为特指apache)的缓冲区.
在apache module的sapi下, flush会通过调用sapi_module的flush成员函数指针, 间接的调用apache的api: ap_rflush刷新apache的输出缓冲区, 当然手册中也说了, 有一些apache的其他模块, 可能会改变这个动作的结果..
有些Apache的模块,比如mod_gzip,可能自己进行输出缓存,这将导致flush()函数产生的结果不会立即被发送到客户端浏览器。
甚至浏览器也会在显示之前,缓存接收到的内容。例如 Netscape浏览器会在接受到换行或 html 标记的开头之前缓存内容,并且在接受到 标记之前,不会显示出整个表格。
一些版本的 Microsoft Internet Explorer 只有当接受到的256个字节以后才开始显示该页面,所以必须发送一些额外的空格来让这些浏览器显示页面内容。
所以, 正确使用俩者的顺序是。 先ob_flush, 然后flush。
当然, 在其他sapi下,,不调用flush也可以, 只不过为了保证你代码的可移植性, 建议配套使用。
在PHP中,我们可以粗略的将缓存分为客户端缓存(Browser缓存),服务器端缓存(Server缓存)。由于PHP是基于B/S架构的,所以,我们可以理解为浏览器端的缓存,服务器端缓存。
在服务器端PHP自带的缓存中,主要可以分为两大类缓存!程序缓存和OB缓存!这也是我们学习服务器端缓存的主要内容!
在PHP中缓存的输出顺序为:
打开了php输出缓存: echo,print -> php output_buffering -> server buffering -> browser buffering -> browser display
未打开php输出缓存: echo,print -> server buffering -> browser buffering -> browser display
浏览器的输出缓存:IE为256Bytes, Chrome与FireFox为1000Bytes,只有输出数据达到了这个长度或者脚本结束浏览器才会将数据输出在页面上。
如何开启OB , 有两个方法
2.1. 在php.ini 配置 ;output_buffering = 4096 这里去掉;号即可
2.2 在php页面中使用 ob_start();
2.3 通过php.ini 打开的,则作用于所有的php页面 , 使用ob_start()打开则只作用于该页面
3.当PHP页面执行到最后,则会把ob缓存的数据(如果有的话), 强制刷新到程序缓存,然后通过apache对数据封装成http响应包,返 回给浏览器
4.如果没有ob,所有的数据直接放入程序缓存
5.header信息不管你是否开启ob,总是放入到程序缓存
1.ob_start
激活output_buffering机制,一旦激活,脚本不再直接输出到浏览器,而是暂时写入php buffering区域。直到脚本运行完毕后,才发送。
2.ob_get_contents
获取php buffering中的数据,注意:要在ob_end_clean()前调用,否则只会得到空字符。
3.ob_end_flush 和 ob_end_clean
ob_end_flush 会输出php buffering 中的数据,但不会清空。
ob_end_clean 不会输出,只会清空php buffering中的数据。
4.ob_flush 、flush、ob_implicit_flush
ob_flush 会刷新php buffering 中的数据到程序缓存
flush 则会刷新程序缓存到浏览器缓存中
ob_implicit_flush 将打开或关闭绝对(隐式)刷送。绝对(隐式)刷送将导致在每次输出调用后有一次刷送操作,以便不再需要对 flush() 的显式调用
OB缓存在各个方面都有应用,但是,本人知道的主要是在两个方面!
a、当网站准备做网站静态化的时候,选择OB缓存是一个不错的选择!
b、解决Warning: Cannot modify header information - headers already sent by的错误!
究其发生错误的原因:是因为响应头和相应主体位置错位导致的!正常情况下,服务器返回给浏览器的相应内容,应该是:响应头+响应主体!
但是,如果我们开启了OB缓存,那么相应头信息(一般也就是header()函数进行设置的信息),会被放入到程序缓存中!
而其他的输出内容,如:echo print_r var_dump 等,都会先被放入OB缓存中!
等程序结束的时候,或者OB缓存关闭的实话,将OB缓存的内容在放入程序缓存中!从而保证响应头信息,始终在响应主体内容之前!