Composer 明确禁止在同一个 autoload 块中混合使用 PSR-0 和 PSR-4;PSR-0 已废弃,遇混合配置时会静默忽略 PSR-0、仅生效 PSR-4,并可能报弃用警告。

Composer 不支持在同一个 autoload 配置块中混合使用 PSR-0 和 PSR-4 —— 这不是“怎么配”的问题,而是设计上明确禁止的。PSR-0 已被废弃(PHP-FIG 在 2014 年正式弃用),composer install 或 composer dump-autoload 遇到同时声明 psr-0 和 psr-4 的配置时,会静默忽略 psr-0,仅生效 psr-4(且可能报 warning)。
为什么 composer.json 里写 psr-0 + psr-4 不起作用
Composer 的 autoloader 构建逻辑是单通道优先级覆盖:加载器生成时,psr-4 映射会被优先注册并接管命名空间前缀;若同一前缀在 psr-0 中也存在映射,它会被完全跳过。这不是 bug,是为避免歧义而做的强制约束。
- 运行
composer dump-autoload -v会看到类似提示:Warning: The PSR-0 autoloading specification is deprecated... - 即使
psr-0路径下有类文件,只要命名空间匹配psr-4规则,就会走 PSR-4 查找逻辑(即按目录结构严格对应) - 旧版 Composer(
老项目要兼容 PSR-0 类库怎么办
不能靠混合配置,必须分层解决:把遗留 PSR-0 类库单独隔离,用 classmap 或 files 加载,或通过 autoload-dev + 条件加载规避冲突。
-
首选 classmap:对 PSR-0 目录执行
composer dump-autoload --classmap-authoritative,它会扫描所有.php文件并生成静态映射表,绕过 PSR 规则解析 -
慎用 files:若只有少量全局函数文件(如
functions.php),可放进"files": ["src/legacy/functions.php"],但无法处理类自动加载 - 不要在 autoload 中写 "MyLegacy\\": "src/legacy/" 同时设 psr-0 和 psr-4 —— 即使路径不同,只要命名空间前缀重叠,PSR-4 就会拦截全部请求
如何安全迁移 PSR-0 到 PSR-4
核心原则:目录结构必须与命名空间一致,且移除下划线转目录分隔符的旧规则。例如 My_Legacy_Foo → My\Legacy\Foo,对应路径从 src/My/Legacy/Foo.php 变为 src/My/Legacy/Foo.php(路径其实一样,但类名必须改)。
- 用
sed或 PHPStorm 的「Rename Class」批量修改类名(注意__autoload、class_alias、字符串反射等硬编码) - 更新
composer.json:{ "autoload": { "psr-4": { "My\\Legacy\\": "src/My/Legacy/" } } } - 运行
composer dump-autoload -o生成优化后加载器,并删掉原psr-0块 - 如果类名无法立即统一(比如第三方包未维护),就别动它,用
classmap加载整个 vendor 子目录
真正麻烦的从来不是配置写法,而是类名和目录结构是否真实符合 PSR-4 语义 —— Composer 只校验结构,不校验语义。一个 psr-4 配置项写得再“对”,只要某个 My\Legacy\Foo 类实际躺在 src/old/My_Legacy_Foo.php 里,它就永远加载不到。










