flysystem本身不依赖composer,但用composer安装和管理是最稳妥方式;手动引入或混用不匹配版本的适配器是出问题的主因,必须严格对齐flysystem与适配器版本。

直接说结论:Flysystem 本身不依赖 Composer,但用 Composer 安装和管理 Flysystem 及其适配器是最稳妥、最可维护的方式;手动引入或混用不同版本的适配器(比如 league/flysystem-aws-s3-v3 和 league/flysystem v1/v2/v3 不匹配)是出问题的头号原因。
确认 Flysystem 版本与适配器版本严格对齐
Flysystem v2 和 v3 的 API 差异大,尤其是构造 Adapter 的方式。v3 强制要求使用 League\Flysystem\Filesystem + League\Flysystem\Adapter\Local 等新路径,而 v2 还支持旧的 League\Flysystem\Adapter\Local(实际是 v1 风格)。Composer 不会自动帮你校验兼容性,全靠你指定。
- 查清当前项目已有的
league/flysystem版本:composer show league/flysystem - 按此版本选对应适配器:v3 用
league/flysystem-aws-s3-v3、league/flysystem-sftp(注意后者 v3 版本号是^3.0,不是^2.0) - 避免混用:不要在 v3 项目里 require
league/flysystem-aws-s3-v3:^1.0,它只适配 Flysystem v1
用 Composer 安装时显式指定适配器而非“全量安装”
有人跑 composer require league/flysystem 后发现 Filesystem 类找不到,是因为这个包只含核心,不含任何适配器 —— 它故意设计成“按需加载”。你必须明确告诉 Composer 你要哪种后端。
- 本地存储:
composer require league/flysystem-local - AWS S3:
composer require league/flysystem-aws-s3-v3 - SFTP:
composer require league/flysystem-sftp - 别装
league/flysystem-bundle(Symfony 专用),除非你真在 Symfony 项目里
初始化 Filesystem 实例时传入 Adapter 而非直接 new Adapter
常见错误是写 new LocalAdapter(...) 然后传给 Filesystem 构造函数 —— 这在 v3 是错的。v3 的 Filesystem 构造函数只接受 League\Flysystem\AdapterInterface 或 League\Flysystem\StorageAttributes,而官方适配器已改用工厂模式或新接口。
- v3 正确写法:
$adapter = new \League\Flysystem\Adapter\Local('/path/to/root'); $filesystem = new \League\Flysystem\Filesystem($adapter); - 但更推荐用
League\Flysystem\Local\LocalFilesystemAdapter(来自league/flysystem-local包):$adapter = new \League\Flysystem\Local\LocalFilesystemAdapter('/path/to/root'); $filesystem = new \League\Flysystem\Filesystem($adapter); - 所有适配器都应走各自包提供的 Adapter 类,而不是自己 new 核心包里的旧类
多个存储共存时,避免全局单例导致配置污染
一个 Filesystem 实例绑定一个 Adapter,也就绑定一种存储。想同时操作本地和 S3,就得创建两个独立实例 —— 别试图复用同一个实例切换底层。
- 错误做法:
$fs->setAdapter($s3Adapter)(v3 没这方法) - 正确做法:分别定义
$localFs和$s3Fs,各自持有自己的 Adapter 和配置 - 如果用容器(如 Laravel 的
app('filesystem.disk')),确保每个 disk 对应独立配置,不要共享root或bucket参数 - 特别注意:S3 的
use_path_style_endpoint、endpoint等参数漏设会导致AccessDenied或NotFound错误,且报错信息不提示缺哪项
最难调的永远不是“怎么写”,而是“哪个版本的类该从哪个命名空间 new”。翻文档前先 composer show,看清楚 vendor 里到底装了什么,比抄示例代码管用十倍。











