当前位置:主页 > PHP开发 > PHP基础 >

PHP的输出缓冲区从入门到精通教程

栏目:PHP基础 来源: 微信小程序开发网 阅读: 2016-12-16
  当我们使用php里面的echo、print_r等打印输出命令时,如果写的代码是正确的话会立马看到结果,例如,在文件phpos.php里面编写如下代码:

<?php
header('content-type: text/html;charset=utf-8');
echo "微信网www.phpos.net";

  显示的内容如下图所示:


  这是非常好理解的,但是,这个过程并不像我们看到的,在浏览器打开这个文件phpos.php后马上显示结果,其实,我们看到的与服务器执行程序时处理的过程是不一样的,服务器接收到请求,然后,把数据输出到浏览器之间有一个处理过程。
 
当浏览器向服务器发出http请求(即打开文件phpos.php就是通过浏览器向服务器发出http请求)的过程如下:

  1)首先要输出的头部header代码信息将被放到php内部缓冲区也就是“程序缓冲区”里面,然后,再把输出的内容“微信网www.phpos.net”放到“ob缓冲”里面。

  2)当phpos.php文件里面的代码全部执行完后,服务器(例如apache)会把“ob缓冲”里面的内容放到“程序缓冲”里面。

  3)最后,把“程序缓冲”里面的内容一下了全部输出到浏览器上面,这样我们就看到了输出的内容了。

  这是上面一个http请求的大体流程,如下图所示:



  从上面的流程图可以看出,当phpos.php文件里面的代码执行完后,会把ob缓冲区的内容全部放入到程序缓冲区,然后,全部显示到浏览器里面。


ob缓冲区的开关

  ob缓冲区是在php.ini文件里面由output_buffering的值决定是开还是关:

  值为Off时: 表示关闭PHP输出缓存

  值为On时: 打开无限大的输出缓存

  如果关闭缓冲区的话,即output_buffering=Off,上图所示的http请求流程将变成:服务器会把所有的header请求和内容都先放到程序缓冲区中,然后,再把这些内容一并输出到浏览器,如下图所示。


注意:如果没有开启ob缓冲区的话,即output_buffering=Off,那么,在文件phpos.php里面编写代码时头部代码就不能与输出的信息顺序颠倒,否则会出错。这是因为输出内容时,通过浏览器发送了http请求放到了程序缓冲区,接下来你又发一个header请求这是不允许的,因为你已经发送http请求,发送后就不允许再去修改http请求了,否则程序会提示错误:Cannot modify header information – headers already sent by;

例如:

<?php
echo "腾讯网www.qq.com";
header('content-type: text/html;charset=utf-8');
echo "微信网www.phpos.net";

  结果如下图所示:


  从上面的错误也可以得出这样的结论:如果您关闭了ob缓冲区,那么,您发送http请求(例如打开某个php文件)必须把header放在最前面,否则,在header前面的输出也会发一次请求,而后面也会发一次请求这样就会重复,程序以为我们要修改发第一次发送的http请求数据,所以,提示上面的错误。

  把上面的代码用图示表示如下:



开启ob缓存

  当开启ob缓存后,header和输出的内容就不会有顺序上的问题,无论在header头部放不放输出代码都不会出错,这是因为输出内容是放在ob缓冲区的,而header的http请求则是在程序缓冲区的两者并不冲突,如第一张图所示。

  当程序没有要输出的内容后,服务器会把ob缓冲区里面的内容放到“程序缓冲区”一起显示到浏览器里面。


ob缓冲区的作用

  也许我们很少直接使用到ob缓冲区,那可能是因为我们很少进行深入的php开发,如果做高级php开发的话,会经常使用到ob缓冲。ob和程序缓冲区到底有什么作用,其实作用非常多,例如,假设您要通过http下载一个800M的视频,如何使用php进行开发,这就要用到ob缓冲区了,假设您想一下子下载下来那先把800M的视频保存到内存中,而php.ini总的memory_limit, 其默认值是8M,所以,不可能一下子读到内存中,也就是不能一下子下载下来,如果有ob内存则可以把800M分成一段一段的视频进行下载,然后,放到ob缓冲区内,这样就可以实现把800M视频下载下来了。

  再举一个缓冲区的应用就是我们在设计网站时,需要设置生成的内容为静态,这时缓冲区就又要用到了,其实,缓冲区的用处非常多,只是我们一般人没有做这些非常底层的开发,所以,对这些没有太多感觉。


输出控制函数

  上面无论是ob缓冲区还是程序缓冲区它们都是计算机内存里面的一块缓冲区域,这里面的内存是可以通过一系统php函数来操作的,例如,通过php函数打开缓冲区、把缓冲区的内容都强制放到程序缓冲区里等操作。

ob缓冲区相关的函数

flush — 刷新输出缓冲
ob_clean — 清空(擦掉)输出缓冲区
ob_end_clean — 清空(擦除)缓冲区并关闭输出缓冲
ob_end_flush — 冲刷出(送出)输出缓冲区内容并关闭缓冲
ob_flush — 冲刷出(送出)输出缓冲区中的内容
ob_get_clean — 得到当前缓冲区的内容并删除当前输出缓。
ob_get_contents — 返回输出缓冲区的内容
ob_get_flush — 刷出(送出)缓冲区内容,以字符串形式返回内容,并关闭输出缓冲区。
ob_get_length — 返回输出缓冲区内容的长度
ob_get_level — 返回输出缓冲机制的嵌套级别
ob_get_status — 得到所有输出缓冲区的状态
ob_gzhandler — 在ob_start中使用的用来压缩输出缓冲区中内容的回调函数。ob_start callback function to gzip output buffer
ob_implicit_flush — 打开/关闭绝对刷送
ob_list_handlers — 列出所有使用中的输出处理程序。
ob_start — 打开输出控制缓冲
output_add_rewrite_var — 添加URL重写器的值(Add URL rewriter values)
output_reset_rewrite_vars — 重设URL重写器的值(Reset URL rewriter values)


ob缓冲函数使用方法

  1)开启ob缓冲区:ob_start();

  2)使用上面的函数处理自己的业务。

实例一

  假设有三个网站分别是:微信网www.phpos.net,百度网www.baidu.com,腾讯网www.qq.com。

  开发要求:使用ob缓冲区技术把上面的微信网址保存到日志文件phpos.log里面,并把微信网址和百度网址显示出来,但是,不显示不保存腾讯网网址,必须使用echo进行输出。

代码如下:
<?php
ob_start();

echo "腾讯网www.qq.com";
header('content-type: text/html;charset=utf-8');

ob_clean();

echo "微信网www.phpos.net";
$$contents = ob_get_contents();
file_put_contents("d:/wamp/www/phpos.log",$$contents);
echo "百度www.baidu.com";

代码分析:

  先开启ob缓存,然后,输出腾讯网址,根据上面的原理腾讯网址保到了ob缓冲区,然后,把header头信息保存到“程序缓冲区”。

  等执行到函数ob_clean()后,这个函数的作用是把ob缓冲区的内容全部清空,所以,这样就把腾讯网址从ob清理掉了。

  然后,把微信网址放到ob缓冲区,然后,通过ob_get_contents()函数(这个函数类似获取文件内容函数file_get_contents())获取到ob缓冲区的内容,并通过函数file_put_contents()把内容保存到了日志文件phpos.log里面。

  最后,又把百度网址保存到ob缓冲区里面,然后,程序再向下执行代码发现没有要输出的内容了,于是,做最后一步“工作”把ob缓冲区的内容全部放到“程序缓冲区”,然后,一并显示到浏览器里面,如下图所示:


  这样就实现了我们的要求只显示百度网址和微信网址,而不显示也不保存腾讯网址,而且把微信网址保存到日志文件phpos.log里面了。


实例二

  要求:把1到10的数值从零开始,每隔一秒输出一个数字。

  这个要求是这样的:每过一秒就显示一个数值,数值从1开始,例如,刚开始显示1,过一秒后显示2,再过一秒后显示3,以此类推。

代码如下:

echo str_repeat('',10240);

for($$i=1;$$i<10;$$i++) {
echo $$i;

flush();
sleep(1);
}


  这里使用了函数flush(),这个函的作用是刷新输出缓冲,有的公司用这个函数来处理类似像股票的实时数据的,只是我们建设网站一般很少用到。

  注意:一些版本的 Microsoft Internet Explorer 只有当接受到的256个字节以后才开始显示该页面,所以必须发送一些额外的空格来让这些浏览器显示页面内容。这就是为什么上面我们要使用str_repeat()函数输出一些空格的原因。


总结:

  1)若开启ob缓冲区,则echo 输出的数据首先放在ob缓冲区里面。

  2)如果是header信息,则把header信息放到程序缓冲区里面。

  3)无论开没有开启ob缓冲区,程序缓冲区一直是开启的。

  4)当页面执行到最后,如果没有输出代码了,则程序会把ob缓冲区的内容都放到程序缓冲区,然后,一并显示到浏览器。