自 PHP 4.3.0 以来,stream_set_write_buffer() 函数一直存在问题。作为一种解决方法,建议使用 php_user_filter 作为输出缓冲区。通过使用以下类,我测量到在通过逐行写入生成大型文本文件的脚本中,性能提高了 50% 以上
class my_output_buffer extends php_user_filter
{
protected static $BUFFER_SIZE = 4096;
function onCreate( ) {
$this->bff = [];
$this->len = 0;
return true;
}
public function filter($in, $out, &$consumed, $closing)
{
$rv = PSFS_FEED_ME; /* 假设没有输出 */
/* 处理输入 */
while ($bucket = stream_bucket_make_writeable($in)) {
/* 存储桶是否太大而无法容纳在缓冲区中? */
$space = static::$BUFFER_SIZE - $this->len;
if ($bucket->datalen >= $space) {
/* 通过将数据放入内部缓冲区来使用数据 */
$this->bff[] = substr($bucket->data, 0, $space);
$this->len += $space;
$overflow = substr($bucket->data, $space);
$ovfl_len = $bucket->datalen - $space;
$consumed += $bucket->datalen;
assert($this->len == static::$BUFFER_SIZE);
/* 创建一个大型存储桶 */
$bucket->data = implode('', $this->bff);
$bucket->datalen = static::$BUFFER_SIZE;
stream_bucket_append($out, $bucket);
$rv = PSFS_PASS_ON; /* 我们有输出! */
/* 处理溢出 */
$this->bff = [$overflow];
$this->len = $ovfl_len;
}
else {
/* 通过将数据放入内部缓冲区来使用数据 */
$this->bff[] = $bucket->data;
$this->len += $bucket->datalen;
$consumed += $bucket->datalen;
}
}
/* 流正在关闭并且我们有数据? */
if ($closing && $this->len > 0) {
/* 创建最后一个存储桶 */
$data = implode('', $this->bff);
$bucket = stream_bucket_new($this->stream, $data);
stream_bucket_append($out, $bucket);
$rv = PSFS_PASS_ON; /* 我们有输出! */
/* 清除内部缓冲区 */
$this->bff = [];
$this->len = 0;
}
return $rv;
}
}
$fp = fopen('foobar.txt', 'w');
/* 启用过滤 */
stream_filter_register('output.buffer', 'my_output_buffer');
stream_filter_append($fp, 'output.buffer');
/* 很多小的写入 */
for ($i = 0; $i < 10000; $i++) {
fwrite($fp, 'x');
}
fclose($fp);