朋友们,大家学习PHP有没有发现这样的问题,就是脚本完全执行完之前,会一直处于请求中。哪怕脚本已执行过echo语句结构了,页面也不会有任何输出,直到脚本完全执行完才会显示所有结果。
就像上图这样的代码,它不会一个数字一个数字显示在页面,而是等到脚本执行完一块显示在页面。看下面的例子:
上面的代码:一个死循环,每隔一秒打印下当前的时间。
PHP脚本默认运行时间最长是30秒,不到30秒页面基本无数据显示,一直处于请求状态:
浏览器的那个“×”表示页面处于请求中。
30秒过后,脚本自动终止,所有的数据才会一块显示在页面:
通过上面的例子可以了解到这样一个知识。echo语句并没有把要显示的数据直接推送到客户端浏览器上,而是把数据先放到一个“地方”存着,等到脚本完全运行完,再把所有的数据一块推送给客户端。这个“地方”就被称为是“输出缓冲区”——buffer,它是一个内存地址空间,为4096(4kb)【在php.ini配置文件中找到output_buffering配 置】。
我们改造下代码,加入ob_flush和flush这两个函数:
这次显示的方式就不一样了,它不会一块输出数据,而是一个一个输出到页面。
具体的效果自己去演示吧。【经过测试,好像只在Apache下有效,在nginx下没有效果】
下面介绍一组函数,可以操作“输出缓冲区”的函数:
flush — 刷新输出缓冲
上面有演示,需要和ob_flush函数一块使用,刷新输出缓冲。我们可以把flush理解为把服务器的缓冲输出。
ob_flush — 冲刷出(送出)输出缓冲区中的内容
ob_flush可以冲刷出“输出缓冲区”的内容,然后有flush推送到客户端浏览器。
ob_clean — 清空(擦掉)输出缓冲区
ob_clean可以把“输出缓冲区”的内容清空掉。
当输出完字母p时清空“输出缓冲区,看浏览器结果:
“q”以前的字母都没有输出。
ob_clean函数可以用于这样的场景:比如用PHP输出一个图像,在header("Content-type:image/png;")之前有内容输出的话就会出错。有时候我们的程序写得很庞大了,很难排查哪个地方有多余或隐藏字符输出,在header函数前用ob_clean清空下“输出缓冲区”就可以解决这样的问题。
ob_end_clean — 清空(擦除)缓冲区并关闭输出缓冲
ob_end_flush — 冲刷出(送出)输出缓冲区内容并关闭缓冲
这两个函数的作用和ob_clean、ob_flush效果差不多,但它们会关闭PHP的输出缓冲区。后面再有输出直接传给服务器,直接用flush函数就可以把输出发送到用户的浏览器。
代码这样写,时间一样可以一个一个显示在页面里。
ob_get_clean — 得到当前缓冲区的内容并删除当前输出缓。
ob_get_contents — 返回输出缓冲区的内容
只是得到输出缓冲区的内容,但不清除它。
利用上面的这两个函数我们常用于什么功能——生成静态页面,把函数返回的字符串写入到特定的文件里。
“.html”文件是一个纯静态页面后缀,从SEO角度出发,搜索引擎更喜欢这种后缀的网址。我们可以通过URL重写实现伪静态,也可以通过ob_get_contents、file_put_contents函数实现生成真的静态页面。由于静态页面只能做纯内容显示,缺乏交互式,会在服务器硬盘里占用空间。加上现在服务器硬件的提高,动态页面与静态页面也没有多少资源消耗差异了,所以很多网站都不再采用静态页面了。像一些大型的新闻站还是用的静态页面。
加深认识:
buffer
buffer是一个内存地址空间,Linux系统默认大小一般为4096(4kb),即一个内存页。主要用于存储速度不同步的设备或者优先级不同的设备之间传办理数据的区域。通过buffer,可以使进程这间的相互等待变少。这里说一个通俗一点的例子,你打开文本编辑器编辑一个文件的时候,你每输入一个字符,操作系统并不会立即把这个字符直接写入到磁盘,而是先写入到buffer,当写满了一个buffer的时候,才会把buffer中的数据写入磁盘,当然当调用内核函数flush()的时候,强制要求把buffer中的脏数据写回磁盘。
同样的道理,当执行echo,print的时候,输出并没有立即通过tcp传给客户端浏览器显示, 而是将数据写入php buffer。php output_buffering机制,意味在tcp buffer之前,建立了一新的队列,数据必须经过该队列。当一个php buffer写满的时候,脚本进程会将php buffer中的输出数据交给系统内核交由tcp传给浏览器显示。所以,数据会依次写到这几个地方:echo/print -> php buffer -> tcp buffer -> browser
php output_buffering
默认情况下,php buffer是开启的,而且该buffer默认值是4096,即4kb。你可以通过在php.ini配置文件中找到output_buffering配置.当echo,print等输出用户数据的时候,输出数据都会写入到php output_buffering中,直到output_buffering写满,会将这些数据通过tcp传送给浏览器显示。你也可以通过ob_start()手动激活php output_buffering机制,使得即便输出超过了4kb数据,也不真的把数据交给tcp传给浏览器,因为ob_start()将php buffer空间设置到了足够大。只有直到脚本结束,或者调用ob_end_flush函数,才会把数据发送给客户端浏览器。
13节代码拓展:
我们再把第13节一个测试代码做下改造,加上7、8、9行代码:
服务端在不知道TCP连接已断的情况下,会继续执行脚本代码。那本节的输出函数会不会影响整个脚本代码的执行?
结果:
楠神第一次的测试结果没有输出456
我原以为是影响到了。于是得出结论:
执行输出控制函数,服务端发现找不到客户端了,TCP连接已断了,所以服务端也就没必要继续执行代码了。
可后来我又陆续做了很多次,发现并没有影响到,每次都输出456。我不知道是不是和什么配置有没有关系,还是说我第一次测试时出现错误了。