细说flush、ob_flush的区别
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 标记的开头之前缓存内容,并且在 接受到 </table> 标记之前,不会显示出整个表格。
一些版本的 Microsoft Internet Explorer 只有当接受到的256个 字节以后才开始显示该页面,所以必须发送一些额外的空格来让这 些浏览器显示页面内容。 所以, 正确使用俩者的顺序是. 先ob_flush, 然后flush, 当然, 在其他sapi下, 不调用flush也可以, 只不过为了保证你代码的可移植性, 建议配套使用.
flush和ob_flush的使用上有一些特别注意的地方,造成无法刷新输出缓冲。
一. flush和ob_flush的正确顺序,先ob_flush再flush,如下:
ob_flush();
flush();
如果Web服务器的操作系统是windows系统,那顺序颠倒或者不使用ob_flush()也不会出现问题。但是在Linux系统上就无法刷新输出缓冲。
二. 使用ob_flush()前,确保前面的内容大小足够4069字符。
一些Web服务器的output_buffering默认是4069字符或者更大,即输出内容必须达到4069字符服务器才会flush刷新输出缓冲,为了确保flush有效,最好在ob_flush()函数前有以下语句:
print str_repeat(" ", 4096);
以确保到达output_buffering值。
下面这段代码应该很常见
<?php
for ($i=1; $i<20; $i++)
{
echo "<font size='10' color='red'>".$i."</font>";
echo '<br>';
ob_flush();
flush();
sleep(1);
}
ob_end_flush();
?>
<?php
for($i=0;$i<10;$i++){
echo $i.'<br />';
flush();
sleep(1);
}
有了解过PHP缓存输出控制函数的朋友肯定对上面这段代码很熟悉,它想实现的效果是每个1秒输出1个数字,完成全部输出需要10秒,不过实际执行中你会发现奇怪的现象,有些人或者有些时候它的表现如你所愿,而有些人或者有些时候却是10秒后才会一次性输出10个数字。我曾经为此抓狂不已,有朋友留言说这个情况往往是因为IE的缓存必须达到256个字符才会输出,可实际上我之前也考虑到IE的情况,可依旧会有时灵时不灵的情况。今天仔细读过手册才明白,这些不可预料的现象是有它的理由的。
原来php.ini中有两个关键参数会影响到php的缓存输出控制:
参数1:output_buffering :on/off 或者整数 。设置为on时,将在所有脚本中使用输出缓存控制,不限制缓存的大小。而设置为整数时,如output_buffering=4096,当缓存数据达到4096字节时会自动输出刷新缓存。而这个参数的不同正是导致以上代码在不同时候执行结果不同的原因。当output_buffering关闭时,脚本所有的输出(echo)都会即时发送到客户端,执行上面代码时就是每秒输出一个数字。而开启output_buffering后,输出内容就会先缓存在服务端,直到脚本结束时才一起发送给客户端。
参数2:implicit_flush:on/off。设定ON意味着,当脚本有输出时,自动立即发送到客户端。相当于在echo后自动加flush()。
php缓存输出控制的相关函数:
ob_start()
第一个参数:回调函数,可选。在缓存输出前可以对其进行过滤或其他处理。最常见的用法是ob_start(‘ob_gzhandler’),即对缓存的数据进行gzip压缩后再发送给客户端。 第二个参数:缓存块的大小,可选。如果被缓存的内容达到或操作缓存块的大小,缓存会自动输出。默认值是0,指不限定大小,缓存到结束为止。还有个特殊值1,代表chunk_size=4096。 第三个参数:是否擦除缓存,可选,默认是true,如果设置为false,则在脚本执行结束前,缓存都不会被清除。
可以使用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函数,这点似乎不常遇到,遇到的时候记得去查手册吧。
flush()和ob_flush()
这两个函数的使用怕是很多人最迷惑的一个问题,手册上对两个函数的解释也语焉不详,没有明确的指出它们的区别,似乎二者的功能都是刷新输出缓存。但在我们文章一开始的代码中如果讲fush()替换成ob_flush(),程序就再不能正确执行了。显然,它们是有区别的,否则也手册中直接说明其中一个是另外一个函数的别名即可了,没必要分别说明。那么它们的区别到底是什么呢?
反复研究了手册的说明,参考了手册中一些人的留言,自己琢磨应该是这样的: 在没有开启缓存时,脚本输出的内容都在服务器端处于等待输出的状态,flush()可以将等待输出的内容立即发送到客户端。 开启缓存后,脚本输出的内容存入了输出缓存中,这时没有处于等待输出状态的内容,你直接使用flush()不会向客户端发出任何内容。而ob_flush()的作用就是将本来存在输出缓存中的内容取出来,设置为等待输出状态,但不会直接发送到客户端,这时你就需要先使用ob_flush()再使用flush(),客户端才能立即获得脚本的输出。
也就是说本文开头的脚本,可以根据缓存开启与否,有如下几种不同的写法:
注:以下代码都未考虑IE缓存必须大于256字节才输出的问题,如在IE下测试,请在代码开始加一句:“echo str_repeat('',256);”
写法1:
output_buffering = off
implicit_flush=off
<?php
for($i=0;$i<10;$i++){
echo $i.'<br />';
flush();
sleep(1);
}
写法2:
output_buffering = on
implicit_flush=off
<?php
for($i=0;$i<10;$i++){
echo $i.'<br />';
ob_flush();
flush();
sleep(1);
}
写法3:
output_buffering = off
implicit_flush=off
<?php
ob_start(); for($i=0;$i<10;$i++){ echo $i.'<br />'; ob_flush(); flush(); sleep(1);
}
写法4:
output_buffering = on implicit_flush=off
<?php
ob_end_flush(); for($i=0;$i<10;$i++){
echo $i.'<br />';
flush();
sleep(1);
}
写法5:
output_buffering = on implicit_flush=off
<?php
ob_end_clean(); for($i=0;$i<10;$i++){ echo $i.'<br />';
flush();
sleep(1);
}
写法6:
output_buffering = on; implicit_flush=on
<?php
ob_end_clean(); //或者ob_end_flush(); for($i=0;$i<10;$i++){ echo $i.'<br />';
sleep(1); }
写法7:
output_buffering = on; implicit_flush=on
<?php
ob_end_clean();
//或者ob_end_flush();
for($i=0;$i<10;$i++){ echo $i.'<br />'; flush(); sleep(1);
}
写法8:
output_buffering = off implicit_flush=on
<?php
for($i=0;$i<10;$i++){ echo $i.'<br />'; sleep(1); }
ob_end_flush():输出当前服务器端缓存的输出数据,并关闭缓存。
ob_end_clean():清空缓存内容,并关闭缓存。
ob_get_flush():将当前服务器端缓存的输出数据以字符串形式返回,并关闭缓存
ob_get_contents():将缓存中保存的内容以字符串形式返回,并保留缓存。
ob_get_length():返回缓存中数据的长度。
ob_get_clean():获取缓存中的数据,请清空缓存,相当于依次执行ob_get_contents()和ob_end_clean()。
ob_implicit_flush():相当于开启php.ini中的implicit_flush参数,立即发送脚本的输出。
ob_gzhandler():使用gzip压缩缓存数据。用于将文本数据压缩后再发送到客户端,可以极大减少数据传输所用的时间,对于提高网站浏览速度帮助很大。通常作为ob_start()的回调函数来使用。
ob_list_handlers():列出所有输出使用的操作方法。
例1:
<?php
ob_start(); echo '周伯通'.'<br>'; var_dump(ob_list_handlers()).'<br>'; ob_end_flush();
输出:
周伯通
array(2) { [0]=> string(22) "default output handler" [1]=> string(22) "default output handler" }
例2:
<?php
ob_start("ob_gzhandler"); echo '周伯通'.'<br>'; var_dump(ob_list_handlers()).'<br>'; ob_end_flush();
输出:
周伯通
array(2) { [0]=> string(22) "default output handler" [1]=> string(12) "ob_gzhandler" }
本次输出,使用了ob_gzhandler的缓存方法。
例3:
<?php
ob_start(create_function('$string','return $string;')); print_r(ob_list_handlers()); ob_end_flush();
将所有的数据输出时,使用的操作操作方法返以数组形式回。如果缓存没有打开,或者已经关闭,此函数只会返回空数组。
细说flush、ob_flush的区别的更多相关文章
- PHP flush()与ob_flush()的区别
buffer ---- flush()buffer是一个内存地址空间,Linux系统默认大小一般为4096(1kb),即一个内存页.主要用于存储速度不同步的设备或者优先级不同的 设备之间传办理数据的区 ...
- 最详细的PHP flush()与ob_flush()的区别详解
buffer ---- flush()buffer是一个内存地址空间,Linux系统默认大小一般为4096(1kb),即一个内存页.主要用于存储速度不同步的设备或者优先级不同的 设备之间传办理数据的区 ...
- [转载]php中sleep,flush,ob_flush函数介绍
<?phpecho str_pad(" ",1024);//当上面这句没有的时候浏览器没有任何输出 直到sleep函数设定的时间结束 才会输出//原因如下面截图for ($i ...
- 细说Debug和Release区别
VC下Debug和Release区别 最近写代码过程中,发现 Debug 下运行正常,Release 下就会出现问题,百思不得其解,而Release 下又无法进行调试,于是只能采用printf方式逐步 ...
- hibernate学习(六) flush()和clean()区别和使用
session.flush()是强制和数据库同步 session.clean()是清除session中的缓存 对于批量数据插入的时候优化:减少cpu和内存(缓存)占用量 @Test public vo ...
- hibernate flush clear的区别
有的时候你执行了更新什么的操作不一定能查出来:没有保存到数据库 以下的缓存是指一级缓存,即session:默认缓存是一级缓存: flush的意思就是执行sql,但是还没有commit,没有持久化:再清 ...
- jsp 中 include指令 用法, <%@ include file="..."%> 和 <jsp:include page="..." flush="true" />的区别?
原文链接https://blog.csdn.net/u012187452/article/details/51779052 1. 什么是jsp 文件? 个人理解. jsp 是一个容器,可以将我们编写 ...
- hibernate的各种保存方式的区别 (save,persist,update,saveOrUpdte,merge,flush,lock)等
hibernate的保存hibernate对于对象的保存提供了太多的方法,他们之间有很多不同,这里细说一下,以便区别:一.预备知识:在所有之前,说明一下,对于hibernate,它的对象有三种状态,t ...
- 【转】NHIBERNATE的各种保存方式的区别 (SAVE,PERSIST,UPDATE,SAVEORUPDTE,MERGE,FLUSH,LOCK)
前言 今天学学习NH这个框架,在新增对象的时候,看见大神用了persist而没有用Save,心中比较疑惑,查阅资料的时候,发现这篇写的非常不错,转载供大家参考. hibernate的保存hiberna ...
随机推荐
- [转]CSS clear both清除浮动
DIV+CSS clear both清除产生浮动 我们知道有时使用了css float浮动会产生css浮动,这个时候就需要清理清除浮动,我们就用clear样式属性即可实现. 接下来我们来认识与学习cs ...
- JavaScript之DOM对象获取(1)
我们在操作html中的节点的时候,第一步就需要获取到对应节点(元素),才能有后续的操作.获取节点的方式有很多 1.document.getElementById(‘id值’) 通过id精确的选中某一个 ...
- 9.代码抽取(adapter)
1 抽取Adapter 共性的方法 2 把getView方法里 和holder相关的逻辑 摘取到Holder代码中 3 把Holder 相关的代码 抽取到BaseHolder中 4 把ada ...
- Git使用详细教程(3):git add, git commit详解
在使用git之前,我们首先要初始化一个git管理的仓库,这里以博客(blog)为例 git init blog 我们进入目录,执行git status查看git状态,可以看到一个新的git管理的项目目 ...
- PHP调用百度天气接口API
//百度天气接口API $location = "北京"; //地区 $ak = "5slgyqGDENN7Sy7pw29IUvrZ"; //秘钥,需要申请,百 ...
- 在谷歌安装扩展程序Axure RP Extension for Chrome后,经常无故损坏,无法使用
最近因为要看需求给的原型图,但需求只给了html格式的文件,没有给可以在Axure软件里看的格式, 所以在谷歌安装了一个Axure RP Extension for Chrome扩展程序在谷歌浏览器看 ...
- [Swift]创建CoreData的两种方式
一.CoreData介绍 CoreData主要分为两部分: 上层是模型层,模型层有NSManagedObjectContext上下文管理着, 底层则是由SQLite实现的持久化部分,通过NSPersi ...
- 《Java 多线程编程核心技术》- 笔记
作为业务开发人员,能够在工作中用到的技术其实不多.虽然平时老是说什么,多线程,并发,注入,攻击!但是在实际工作中,这些东西不见得用得上.因为,我们用的框架已经把这些事做掉了. 比如web开发,外面有大 ...
- C语言那年踩过的坑--局部变量,静态变量,全局变量在内存中存放的位置
先看几个概念: 1.bss是英文block started by symbol的简称,通常是指用来存放程序中未初始化的全局变量的一块内存区域,在程序载入时由内核清0.bss段属于静态内存分配.它的初始 ...
- spring boot -junit单元测试方法示例
package com.example.zs; import com.example.zs.mapper.UserMapper; import com.example.zs.pojo.User; im ...