Composer自动加载优先级由类型固定顺序决定:psr-4先于classmap,files为强制前置载入;psr-4命中即止,classmap不触发;优化模式下仅依赖classmap单一映射。

Composer 的自动加载优先级不是靠“设置”决定的,而是由 autoload 配置类型本身决定的——不同类型的自动加载规则有固定执行顺序,且不能手动调整优先级。
autoload 类型的硬性执行顺序
Composer 在生成 vendor/autoload.php 时,会按以下固定顺序注册自动加载器(从高优先级到低):
-
psr-4和psr-0:类名匹配失败才继续往下走 -
classmap:基于预生成的映射表,不依赖命名空间或文件路径,但需提前扫描 -
files:总是无条件加载,优先级最低,但实际“最先执行”(因为它是 require 语句,不是延迟加载)
注意:files 不是“最后尝试”,而是每次请求都立即加载,它不参与类查找流程,所以严格来说不属于“优先级竞争”,而是“强制前置载入”。真正影响 new Foo() 查找顺序的是前两类。
psr-4 和 classmap 同时存在时谁赢?
当一个类同时被 psr-4 规则和 classmap 映射命中时,psr-4 加载器先触发;如果它返回了文件(即使该文件不存在或语法错误),classmap 就不会被调用。这是由 autoloaders 的注册顺序和 SPL 的 __autoload / spl_autoload_call 机制决定的。
- Composer 把
psr-4加载器注册在classmap之前 - 一旦某个加载器成功返回真实存在的 PHP 文件路径,SPL 就停止后续调用
- 所以
psr-4“赢”不是因为它更聪明,只是它排在前面
{
"autoload": {
"psr-4": {
"App\\": "src/"
},
"classmap": ["src/DeprecatedHelper.php"]
}
}
上面配置中,new App\Foo() 一定走 src/Foo.php;哪怕 classmap 里也记录了 App\Foo → legacy/Foo.php,也不会生效。
如何绕过 psr-4 强制走 classmap?
没有直接方式“降级”psr-4 优先级,但可通过以下方式间接控制:
- 把想优先加载的类从
psr-4路径中移出(例如改放lib/),再单独加进classmap - 使用
files手动 require 特定类文件(适合工具类、函数库) - 在
psr-4映射中排除冲突目录,再用classmap补上(需运行composer dump-autoload)
常见误操作:试图在 psr-4 中写两个重叠前缀(如 "App\\" 和 "App\\Legacy\\"),这会导致后注册的覆盖前注册的——但 Composer 会合并它们,不会报错,结果不可控。
dump-autoload 的 --optimize 会影响顺序吗?
不会。启用 --optimize(或 --classmap-authoritative)只是把所有 psr-4/psr-0 规则转成 classmap 形式,生成一个大映射表,然后禁用动态路径解析。此时:
- 不再逐个检查
psr-4规则,只查 classmap 表 - 所有类查找退化为 O(1) 哈希查找,但失去对新文件的自动感知
- 原始配置顺序彻底失效,只剩 classmap 单一来源
也就是说,开启优化后,“优先级”概念消失,只有“是否在 classmap 中”这一个判断标准。
真正需要关注的不是怎么调顺序,而是别让不同 autoload 类型映射同一个类名——Composer 不校验冲突,运行时报 Cannot declare class XXX, because the name is already in use 才暴露问题。










