PHP 怎么模拟文件系统

wen PHP项目 3

本文目录导读:

PHP 怎么模拟文件系统

  1. 使用内存文件系统(推荐)
  2. 使用自定义流包装器
  3. 使用第三方库
  4. 实现简单的内存文件系统类
  5. 使用 ZIP 作为虚拟文件系统
  6. 使用虚拟文件系统协议封装
  7. 选择建议

在 PHP 中模拟文件系统主要有以下几种方法,我会详细介绍每种方法及其适用场景:

使用内存文件系统(推荐)

使用 php://memoryphp://temp

<?php
// 在内存中创建虚拟文件
$fp = fopen('php://memory', 'r+');
fwrite($fp, 'Hello World');
rewind($fp);
echo stream_get_contents($fp); // 输出: Hello World
fclose($fp);
// php://temp 会自动切换到临时文件(当数据超过2MB时)
$fp = fopen('php://temp', 'r+');
fwrite($fp, str_repeat('A', 3000000)); // 3MB 数据
rewind($fp);
echo strlen(stream_get_contents($fp)); // 3000000
fclose($fp);

使用自定义流包装器

通过实现 StreamWrapper 接口来创建虚拟文件系统:

<?php
class VirtualFileSystem implements StreamWrapper {
    private $files = [];
    private $currentDir = '';
    public function stream_open($path, $mode, $options, &$opened_path) {
        $this->currentDir = $path;
        return true;
    }
    public function stream_read($count) {
        // 实现读取逻辑
        return '';
    }
    public function stream_write($data) {
        // 实现写入逻辑
        return strlen($data);
    }
    // 其他必须实现的方法...
}
// 注册自定义协议
stream_wrapper_register('vfs', 'VirtualFileSystem');
// 使用虚拟文件系统
$file = file_get_contents('vfs://somefile.txt');

使用第三方库

League\Flysystem - 最流行的选择

<?php
require 'vendor/autoload.php';
use League\Flysystem\Filesystem;
use League\Flysystem\InMemory\InMemoryFilesystemAdapter;
// 创建内存文件系统
$filesystem = new Filesystem(new InMemoryFilesystemAdapter());
// 使用文件系统
$filesystem->write('test.txt', 'Hello World');
$content = $filesystem->read('test.txt');
echo $content; // Hello World
$filesystem->createDirectory('subdir');
$filesystem->write('subdir/file2.txt', 'Another file');
// 检查文件是否存在
if ($filesystem->fileExists('test.txt')) {
    echo '文件存在';
}

Symfony Filesystem 组件

<?php
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Filesystem\Exception\IOExceptionInterface;
$fs = new Filesystem();
try {
    // 创建目录
    $fs->mkdir('/tmp/virtual_dir');
    // 写入文件
    $fs->dumpFile('/tmp/virtual_dir/file.txt', '内容');
    // 读取文件
    $content = file_get_contents('/tmp/virtual_dir/file.txt');
    // 清理
    $fs->remove('/tmp/virtual_dir');
} catch (IOExceptionInterface $exception) {
    echo "错误: " . $exception->getMessage();
}

实现简单的内存文件系统类

<?php
class MemoryFileSystem {
    private $files = [];
    private $directories = ['./'];
    public function write($path, $content) {
        $this->files[$path] = $content;
        return true;
    }
    public function read($path) {
        if (!isset($this->files[$path])) {
            throw new Exception("文件不存在: $path");
        }
        return $this->files[$path];
    }
    public function exists($path) {
        return isset($this->files[$path]);
    }
    public function delete($path) {
        if (!isset($this->files[$path])) {
            throw new Exception("文件不存在: $path");
        }
        unset($this->files[$path]);
        return true;
    }
    public function listDirectory($dir = '.') {
        $result = [];
        foreach ($this->files as $path => $content) {
            if (strpos($path, $dir . '/') === 0) {
                $result[] = $path;
            }
        }
        return $result;
    }
    public function getInfo($path) {
        if (!isset($this->files[$path])) {
            return false;
        }
        return [
            'size' => strlen($this->files[$path]),
            'modified' => time(),
            'content' => $this->files[$path]
        ];
    }
}
// 使用示例
$vfs = new MemoryFileSystem();
$vfs->write('/var/log/app.log', "日志内容\n第二行");
$vfs->write('/var/config.json', '{"key": "value"}');
// 读取文件
echo $vfs->read('/var/log/app.log');
// 检查文件
var_dump($vfs->exists('/var/config.json')); // true
// 列出目录
$files = $vfs->listDirectory('/var');
print_r($files);

使用 ZIP 作为虚拟文件系统

<?php
// 创建内存中的 ZIP 文件作为虚拟文件系统
$zip = new ZipArchive();
$tempFile = tempnam(sys_get_temp_dir(), 'vfs_');
$zip->open($tempFile, ZipArchive::CREATE);
// 添加文件
$zip->addFromString('config/database.php', '<?php return [];');
$zip->addFromString('public/index.php', '<?php echo "Hello";');
$zip->close();
// 使用 ZIP 流读取
$zip = new ZipArchive();
$zip->open($tempFile);
echo $zip->getFromName('config/database.php');
$zip->close();
// 清理
unlink($tempFile);

使用虚拟文件系统协议封装

<?php
class StreamVFS {
    private static $registry = [];
    public static function register() {
        stream_wrapper_register('vfs', __CLASS__);
    }
    public static function setFile($path, $content) {
        self::$registry[$path] = $content;
    }
    public static function getFile($path) {
        return isset(self::$registry[$path]) ? self::$registry[$path] : null;
    }
    // 流包装器必需的方法
    public function stream_open($path, $mode, $options, &$opened_path) {
        return true;
    }
    public function stream_read($count) {
        return '';
    }
    public function stream_write($data) {
        return strlen($data);
    }
    public function stream_eof() {
        return true;
    }
    public function stream_tell() {
        return 0;
    }
    public function stream_seek($offset, $whence) {
        return true;
    }
    public function stream_stat() {
        return [];
    }
    public function stream_close() {}
}
StreamVFS::register();
StreamVFS::setFile('/test.txt', 'Hello Virtual World');
echo file_get_contents('vfs://test.txt');

选择建议

  1. 测试场景:使用 PHPUnit 的虚拟文件系统(vfsStream)库
  2. 简单演示:使用 php://memory 或自定义类
  3. 复杂应用:使用 Flysystem 的适配器模式
  4. 需要真实文件操作:使用临时目录 + 真实文件系统

PHPUnit 中的虚拟文件系统

<?php
use org\bovigo\vfs\vfsStream;
use PHPUnit\Framework\TestCase;
class MyTest extends TestCase {
    public function testFileOperations() {
        // 创建虚拟文件系统
        $root = vfsStream::setup('home');
        // 创建虚拟文件
        vfsStream::newFile('test.txt')
            ->at($root)
            ->setContent('Hello');
        // 测试文件操作
        $this->assertFileExists(vfsStream::url('home/test.txt'));
        $this->assertEquals('Hello', file_get_contents(vfsStream::url('home/test.txt')));
    }
}

这些方法各有优缺点,选择时需要考虑:

  • 性能和内存使用
  • 功能需求(权限、目录操作等)
  • 易用性和维护成本
  • 是否需要在测试环境使用

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