这一个月以来,我都忙着写后端代码,今天写这篇文单呢,主要是因为我觉得有必要来聊聊关于PHP缓冲这个概念以及它在项目中的运用。PHP缓冲是什么东西?
很多人都没有听过这个,包括工作过一段时间的PHP程序员都没有。我们看到的见面渲染出来的效果是第一时间的吗?有的是,有的不是。首先,缓冲区这个东西里面的东西不会第一时间输出到客户端,如果你打开它的话。
缓冲在应用程序中最主要的作用无非就两种,其一是为了减轻高速运转CPU的压力,其二则是用来解决I/O设备缓慢的弊端,这在很多地方都派上了用场。当我们要了解关于PHP缓冲区的知识时,首先得知道入口在哪儿。
从缓冲到输出的过程
当PHP程序在运行输出操作时,程序本身会自动将内容放入缓冲区,PHP接收到输出指令时会将内容输出给服务器,这里以apache服务器为例,那么服务器又会将内容缓冲到自身的缓冲区内,等接到apache输出指令时,再将内容输出到客户端。
从这个过程中,可以看到,一个缓冲区的内容想要输出到客户端,必须先到PHP自身的缓冲区转到apache,再到客户端展示出来。这是一个很重要的流程跟概念。PHP缓冲起到哪些作用?
有没有发现当我们在做文件流下载时通常会输出一些内容(里面可能包含自定义的参数,如果使用了header方法,且没有缓冲区的话,客户端会收到关于报错信息的response。因为,如果没有用缓冲的话,那么在第一次输出内容时会立即执行;第二种就是输出内容后,又设置了header信息。
此时,如果没有缓冲的话,则前端客户端会收到一条错误消息,提示关于已经有过header了,因为之前输出的内容会自动带header到客户端,而缓冲区的实现则可以实现输出内容,又可以设置header部分的内容,因为缓冲区输出的跟header是不冲突的,当header设置时,PHP会直接将消息推到apache然后传给客户端,而要传输的数据则会先到缓冲区等待发送,故不影响。
当传输文件过大时,没有缓冲区的话那是需要一次性读完后,再一次性传给客户端,这样的体验太差了,并且PHP的默认配置memory_limit也不支持,因为这个默认值是8M,也就是说最大的传输数据大小值为8M,为了避免此配置冲突,缓冲可以分片发送,每读取一部分就放缓冲区再进行传输到客户端。
如果做过静态文件的优化就会明白,静态处理是不需要PHP程序每次都去处理的,第一次处理过后就放入到缓冲区了,当下次来访问此静态页面时服务器会自动从缓存里取,而这就需要用到缓冲区去设置了。
关于PHP缓冲配置的几个选项
1、output_buffering
这个配置是PHP本身的缓冲区配置,有三个值,分别是on/off/某一个具体字节大小
on 顾名思义是开启缓冲区
off 是关闭
最后一个意思是可以写具体的某个字节大小,与此同时会自动开启缓冲区,也就是说到了这个大小的字节时会自动输出数据到apache,也叫刷新,清空缓冲区
2、implicit_flush
这个就是负责配置apache缓冲区的,两个配置参数on/off
on 开启的话,会自动刷新缓冲区将数据输出给客户端
off 则相反,需要等待传输指令,也就是下令传输到客户端,不会自动执行PHP操作关于缓冲区的函数
ob_implicit_flush 是否自动刷新缓冲区,注意这个是apache服务器的
flush 刷新指令,或者说是传输指令,让apache服务器清空,刷新,传输数据到客户端
ob_start 打开缓冲区,这个函数一运行,php.ini配置文件里的output_buffering将失效
ob_flush 指令,将通知php本身缓冲区传输到apache服务器
ob_clean 清除缓冲区内容
ob_end_clean 清除并关闭缓冲区
ob_end_flush 传输数据到apache服务器,然后关闭缓冲区
ob_get_clean 获取缓冲区内容并关闭缓冲区
ob_get_contents 获取输出缓冲区里的内容
ob_get_flush 获取缓冲区里的内容,并且发送到apache服务器
ob_get_length 获取缓冲区里内容长度
ob_list_handlers 运行ob_start函数的回调函数名称
ob_gzhandler 运行ob_start函数的回调函数名称,注意该函数在写入缓冲区之前会对内容进行gzip与zlib压缩处理
实际应用的问题
这里说几个实际中用到时发生的问题,比如nginx服务器有配置fastcgi_buffer_size 4k 也就是说只有当缓冲区到了4K时才会刷新输出,所以当你调用flush函数时一定要注意,否则看不到效果。
关于apache模块mod_gzip,当你flush后通知apache刷新缓冲区,这时apache发现此模块开启是需要压缩,就会输到mod_gzip的缓冲区中去,这时候内容是不会立马到客户端的,需要注意一下这点,如无需要就不要开启,如果有需要压缩在传输的话建议使用ob_gzhandler
本文原创,未经允许不得转载!
责任编辑: