PHP 怎么PHP自定义流

wen PHP项目 3

本文目录导读:

PHP 怎么PHP自定义流

  1. 基本概念
  2. 完整示例:实现一个 JSON 文件流
  3. 更简单的内存流示例
  4. 常用的流方法列表
  5. 注册和使用技巧
  6. 实际应用场景
  7. 注意事项

PHP 自定义流(Custom Stream Wrapper)是一种强大的功能,允许你注册自己的流处理器来处理 file://http:// 等协议之外的任意协议。

基本概念

自定义流的核心是实现 streamWrapper,然后通过 stream_wrapper_register() 注册。

完整示例:实现一个 JSON 文件流

<?php
class JsonStreamWrapper {
    private $data = '';
    private $position = 0;
    private $filename = '';
    private $mode = '';
    // 打开流
    public function stream_open($path, $mode, $options, &$opened_path) {
        $this->filename = $path;
        $this->mode = $mode;
        $this->position = 0;
        // 从文件读取 JSON 数据
        $filepath = substr($path, 7); // 去掉 "json://"
        $content = @file_get_contents($filepath);
        $this->data = $content ?: '{}';
        return true;
    }
    // 读取数据
    public function stream_read($count) {
        $data = substr($this->data, $this->position, $count);
        $this->position += strlen($data);
        return $data;
    }
    // 写入数据
    public function stream_write($data) {
        $this->data = substr($this->data, 0, $this->position) . 
                      $data . 
                      substr($this->data, $this->position + strlen($data));
        $this->position += strlen($data);
        return strlen($data);
    }
    // 获取当前位置
    public function stream_tell() {
        return $this->position;
    }
    // 定位
    public function stream_seek($offset, $whence) {
        switch ($whence) {
            case SEEK_SET:
                $this->position = $offset;
                break;
            case SEEK_CUR:
                $this->position += $offset;
                break;
            case SEEK_END:
                $this->position = strlen($this->data) + $offset;
                break;
        }
        return true;
    }
    // 检查是否到末尾
    public function stream_eof() {
        return $this->position >= strlen($this->data);
    }
    // 关闭流
    public function stream_close() {
        // 如果是写入模式,保存数据
        if (strpos($this->mode, 'w') !== false || strpos($this->mode, 'a') !== false) {
            $filepath = substr($this->filename, 7);
            file_put_contents($filepath, $this->data);
        }
    }
    // 获取流统计信息
    public function stream_stat() {
        return ['size' => strlen($this->data)] + stat($this->filename);
    }
    // 清空流
    public function stream_flush() {
        $filepath = substr($this->filename, 7);
        file_put_contents($filepath, $this->data);
        return true;
    }
}
// 注册流包装器
stream_wrapper_register('json', 'JsonStreamWrapper');
// 测试使用
$file = fopen('json://data/config.json', 'r+');
$content = stream_get_contents($file);
echo "读取内容: " . $content;
// 写入数据
fwrite($file, '{"name": "John", "age": 30}');
fclose($file);

更简单的内存流示例

<?php
class MemoryStream {
    private $data = '';
    private $pos = 0;
    public function stream_open($path, $mode, $options, &$opened_path) {
        $this->data = '';
        $this->pos = 0;
        return true;
    }
    public function stream_read($count) {
        $ret = substr($this->data, $this->pos, $count);
        $this->pos += strlen($ret);
        return $ret;
    }
    public function stream_write($data) {
        $this->data .= $data;
        return strlen($data);
    }
    public function stream_tell() {
        return $this->pos;
    }
    public function stream_seek($offset, $whence) {
        switch ($whence) {
            case SEEK_SET: $this->pos = $offset; break;
            case SEEK_CUR: $this->pos += $offset; break;
            case SEEK_END: $this->pos = strlen($this->data) + $offset; break;
        }
        return true;
    }
    public function stream_eof() {
        return $this->pos >= strlen($this->data);
    }
    public function stream_close() {
        // 可以把数据存到某个地方
        $_SESSION['memory_stream_data'] = $this->data;
    }
    public function stream_stat() {
        return [];
    }
}
// 注册
stream_wrapper_register('memory', 'MemoryStream');
// 使用
$handle = fopen('memory://temp', 'w');
fwrite($handle, 'Hello, World!');
fclose($handle);
$handle = fopen('memory://temp', 'r');
echo stream_get_contents($handle); // 输出: Hello, World!
fclose($handle);

常用的流方法列表

方法 用途
stream_open() 打开流时调用
stream_read() 读取数据
stream_write() 写入数据
stream_tell() 获取当前位置
stream_seek() 定位
stream_eof() 检查末尾
stream_close() 关闭流
stream_stat() 获取文件统计信息
url_stat() 获取路径信息
stream_flush() 刷新缓冲区
unlink() 删除
mkdir() 创建目录
rmdir() 删除目录
rename() 重命名

注册和使用技巧

<?php
// 注册时可以指定前缀
stream_wrapper_unregister('json'); // 先注销已存在的
stream_wrapper_register('json', 'JsonStreamWrapper');
// 检查是否已注册
$wrappers = stream_get_wrappers();
var_dump(in_array('json', $wrappers));
// 也可以注册到全局
stream_wrapper_restore('json'); // 恢复默认包装器
// 使用示例
$context = stream_context_create([
    'json' => [
        'option1' => 'value',
        'option2' => 'value'
    ]
]);
$data = file_get_contents('json://path/to/file.json', false, $context);

实际应用场景

数据库流

class DBStream {
    private $connection;
    private $result;
    public function stream_open($path, $mode, $options, &$opened_path) {
        // 解析路径: db://table/query
        preg_match('/db:\/\/(\w+)\/(.+)/', $path, $matches);
        $db = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
        $this->connection = $db;
        $this->result = $db->query($matches[2]);
        return true;
    }
    public function stream_read($count) {
        if ($row = $this->result->fetch(PDO::FETCH_ASSOC)) {
            return json_encode($row) . "\n";
        }
        return '';
    }
}

加密流

class EncryptedStream {
    private $key;
    private $data;
    public function stream_open($path, $mode, $options, &$opened_path) {
        $this->key = 'secret_key';
        $this->data = '';
        return true;
    }
    public function stream_write($data) {
        $this->data .= openssl_encrypt($data, 'AES-128-CBC', $this->key);
        return strlen($data);
    }
}

注意事项

  1. 性能考虑:不要滥用自定义流,它比普通文件操作慢
  2. 错误处理:确保实现必要的方法,否则可能有未定义行为
  3. 权限检查:在自己的流包装器中检查权限
  4. 资源清理:在 stream_close() 中释放资源
  5. PHP 版本:不同 PHP 版本可能有细微差异

自定义流非常适合用于数据处理管道、资源抽象、或者为特定格式提供统一接口等场景。

抱歉,评论功能暂时关闭!