Composer 2.0+ 已彻底移除 PSR-0 支持,psr-0 字段被静默忽略;老项目需手动注册 spl_autoload_register 或改用 classmap,并确保 Docker 镜像中路径正确、dump-autoload 显式执行。

Composer 本身不生成符合 PSR-0 标准的类,它只负责加载——而且从 Composer 2.0+ 开始,连加载都不支持了。所谓“生成”,其实是你手动写类时要遵循 PSR-0 的文件路径与类名映射规则;而“老项目升级”和“镜像构建”中真正卡住人的,从来不是怎么写类,而是 autoload 怎么配、在哪配、配了有没有生效。
PSR-0 类文件结构怎么写才对
PSR-0 要求类名中的下划线 _ 必须转为目录分隔符,且整个类名(含前缀)全部小写后拼上 .php。比如类名 Swift_Mime_SimpleMessage,对应路径必须是 swift/mime/simplemessage.php,不能是 Swift/Mime/SimpleMessage.php(那是 PSR-4),也不能是 swift_mime_simplemessage.php(扁平命名)。
- 前缀部分(如
Swift_)需对应真实存在的子目录,比如vendor/swiftmailer/swiftmailer/lib/classes/swift/ - 类文件里不能有
namespace声明——PSR-0 本质是无命名空间时代的约定,靠下划线模拟层级 - 文件名大小写必须全小写,哪怕类名首字母大写(
SimpleMessage→simplemessage.php) - 如果类名不含下划线(如
Helper),PSR-0 规则不适用,得靠classmap或手动require_once
composer.json 里写 psr-0 字段根本没用
Composer 2.0+ 已彻底删除 PSR-0 解析逻辑,psr-0 字段会被静默忽略,既不报错也不生成任何映射代码。运行 composer dump-autoload 后,vendor/composer/autoload_psr0.php 文件压根不会出现。
- 即使你写成
{"autoload": {"psr-0": {"Swift_": "vendor/swiftmailer/swiftmailer/lib/classes/"}}},也完全无效 - Composer 会直接跳过该字段,连 warning 都不输出(尤其 v2.5+)
- 降级到 Composer 1.x 是唯一能让
psr-0字段起作用的方式,但 1.x 已停止维护,不建议用于新部署或容器镜像
老项目在 Composer 2.x 下加载 PSR-0 类的实操方案
只有两种可靠路径:手动注册 spl_autoload_register,或改用 classmap。前者适合结构稳定、路径明确的旧库(如 swiftmailer/swiftmailer:v5.4),后者适合少量扁平类文件。
- 手动注册必须放在
require_once __DIR__ . '/vendor/autoload.php';之后,否则会被 Composer 的 autoloader 拦截 - 路径必须硬编码实际位置,比如
__DIR__ . '/vendor/swiftmailer/swiftmailer/lib/classes/',不能用变量或相对路径泛化 -
classmap方式更简单:在composer.json中加"classmap": ["vendor/swiftmailer/swiftmailer/lib/classes/"],再执行composer dump-autoload - 注意
classmap不支持动态新增类——每次增删类文件都得重新dump-autoload,CI/CD 流水线里容易漏掉这步
Docker 镜像里 PSR-0 类加载失败的真实原因
镜像构建时最常见的错误不是 autoload 配错了,而是源码根本没 COPY 进去,或者路径层级不对。比如你写了 COPY ./src /app/src,但 .dockerignore 里有一行 src/,结果 /app/src 是空的——composer dump-autoload 不报错,运行时才抛 Class not found。
- 所有 PSR-0 相关路径(包括
spl_autoload_register里的$file构造逻辑)必须基于镜像内最终路径,不是宿主机路径 - 不要依赖
composer install自动刷新 autoload —— 它只装包,不重生成映射;必须显式执行composer dump-autoload -o - 若用了
classmap,确保扫描目录在镜像中真实存在且可读,否则生成的autoload_classmap.php里对应条目为空
最易被忽略的点:PSR-0 兼容不是配置问题,是运行时补丁问题;你在 index.php 里少写一行 spl_autoload_register,或者 Dockerfile 里漏掉一次 dump-autoload,整个 autoload 链就断了——它不会提示你哪里错了,只会安静地抛出 Class not found。


















