My blog

PHP的多级缓冲机制

2024/07/15

在 PHP 中,缓冲区(output buffering)是一种将输出数据暂存到内存中的技术。 它可以将脚本生成的所有输出数据保存在缓冲区中,直到缓冲区被显式地清空或者达到一定的大小限制时才会输出到客户端。

  • ob_clean — 清空(擦掉)输出缓冲区
  • ob_end_clean — 清空(擦除)缓冲区并关闭输出缓冲
  • ob_end_flush — 冲刷出(送出)输出缓冲区内容并关闭缓冲
  • ob_flush — 冲刷出(送出)输出缓冲区中的内容
  • ob_start — 打开输出控制缓冲

我们来段代码测试以下:

1
2
3
4
5
6
7
8
9
10
<?php
ob_start();
echo 'level 1<br/> ';
ob_start();
echo 'level 2<br/> ';
ob_start();
echo 'level 3<br/> ';
ob_end_flush();
ob_end_flush();
ob_end_flush();

结果如下,可以看到都正常输出了

当程序修改一下,修改一个ob_end_flush() 变成 ob_end_clean() 成为以下这个,

1
2
3
4
5
6
7
8
9
10
<?php
ob_start();
echo 'level 1<br/> ';
ob_start();
echo 'level 2<br/> ';
ob_start();
echo 'level 3<br/> ';
ob_end_clean();//修改处
ob_end_flush();
ob_end_flush();

结果如下,

可能你会认为ob_end_clean()会清除与他最近的ob_start()的输出;其实这个说法不是很全面,看下面的例子

1
2
3
4
5
6
7
8
9
10
<?php
ob_start();
echo 'level 1<br/> ';
ob_start();
echo 'level 2<br/> ';
ob_start();
echo 'level 3<br/> ';
ob_end_clean(); //第一次修改
ob_end_flush();
ob_end_clean(); //第二次修改

这次什么输出都没有了
中间不是有一个ob_flush()吗?按理来说应该是输出 level2 的。

其实造成这样的主要原因是输出的多级缓冲机制。这个程序例子有三个ob_start(),就意味着他有3个缓冲区A,B,C,而其实php程序本身也有一个最终输出的缓冲区,我们就把他叫做F。

在这个程序中他这几个缓冲区是有一定层次的,C->B->A->F,F层次最高,是程序最终的输出缓冲,我们按上面的程序来进行讲解。下面是从上至下的顺序来的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
ob_start();//F:null
//然后新建缓冲区A。 A: null -> F:null

echo 'level 1<br/> ';//此时程序有输出,输出进入最低的缓冲区A A: 'level 1<br/>' -> F:null


ob_start(); //新建缓冲区B 。 B:null -> A: 'level 1<br/>' -> F:null

echo 'level 2<br/> ';//程序有输出,输出进入最低的缓冲区B B:'level 2<br/> ' -> A: 'level 1<br/>' ->F:null


ob_start(); //新建缓冲区C C:null B:'level 2<br/> ' A: 'level 1<br/>' -> F:null

echo 'level 3<br/> ';//程序有输出,输出进入最低的缓冲区C C:'level 3<br/> ' -> B:'level 2<br/> ' -> A: 'level 1<br/>' -> F:null


ob_end_clean(); //缓冲区C被清空并关闭。 B:'level 2<br/> ' -> A: 'level 1<br/>' -> F:null
ob_end_flush(); //缓冲区B输出到上一级的缓冲区A并关闭。 A: 'level 1<br/>level 2<br/> ' -> F:null
ob_end_clean(); //缓冲区A被清空并关闭。 此时缓冲区A的东西还没真正输出到最终的F中,因此也就整个程序也就没有任何的输出了。

也就是说,当我们多次建立新缓冲区,缓冲区们会根据建立先后去组成多级的缓冲区,每次接受输出的时候都相应的进入最低的(建立时间最晚)的缓冲区,
而到了最后面清空或者输出缓冲区,都是按照顺序从最低的那级缓冲区进行操作,flush就是输出至下一级缓冲区,clean就是讲当前处理的最低一块缓冲区的输出置为null,

最后附上一些关于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
CATALOG