Composer 2.2+ 支持 exclude-from-classmap 精确排除 classmap 中的类文件,仅对 classmap 生效,路径需相对于根目录且区分大小写,不支持通配符;排除后仍被加载常见于其他 autoloader 干预、硬引用或 OPCache 未刷新。

composer.json 里用 autoload.exclude-from-classmap 排除类文件
Composer 默认会把 autoload.classmap 或 autoload.ps4 扫到的所有 PHP 文件都写进 vendor/composer/autoload_classmap.php,但有些类(比如测试桩、废弃兼容层、CLI 工具类)你根本不想被自动加载——这时不能靠删文件或改命名空间,得让 Composer 主动跳过。
从 Composer 2.2 开始支持 exclude-from-classmap 字段,它只对 classmap 类型生效,且必须写在 autoload 或 autoload-dev 下:
"autoload": {
"classmap": ["src/"],
"exclude-from-classmap": ["src/Tests/", "src/Utils/LegacyHelper.php"]
}
- 路径是相对于项目根目录的,必须带尾部斜杠表示目录(如
"src/Tests/"),否则不匹配 - 不支持通配符(
*或**),只能写具体路径或文件名 - 如果类同时被
psr-4和classmap扫到,排除只影响 classmap 条目,不影响 PSR 自动加载逻辑
为什么不用 autoload.files 替代?
有人想绕开 classmap,干脆把要排除的类全扔进 autoload.files,再手动 require ——这反而更危险。
-
autoload.files是无条件全局加载的,每次请求都会执行,哪怕你根本没用到那些类 - 如果文件里有副作用(比如定义常量、修改 ini 设置、触发
register_shutdown_function),会导致不可预期行为 - 和
exclude-from-classmap的“按需不加载”逻辑完全相反,属于倒因为果
排除后仍被加载?检查是否被其他 autoloader 干预
即使配置正确,某些类还是被加载了,常见原因有:
- 框架或扩展自己注册了额外 autoloader(比如 Laravel 的
Illuminate/Foundation/ProviderRepository.php会预加载服务提供者) - 用了
require_once或include硬引用了被排除的文件 -
composer dump-autoload -o后没清空 OPCache,旧 classmap 缓存还在生效(PHP 8.0+ 尤其明显) - 排除路径写错了大小写(Linux 下敏感),例如写了
"Src/Tests/"但实际是"src/Tests/"
想彻底禁用某类命名空间?别碰 Composer,改代码调用逻辑
Composer 不提供“禁止加载某个命名空间”的能力。如果你发现 App\Legacy\* 总是被意外引入,问题不在自动加载配置,而在业务代码里:
- 检查是否有
new App\Legacy\OldService()或class_alias()显式触发 - IDE 或静态分析工具(如 PHPStan)可能误报“未使用类”,但它不是 Composer 加载行为
- 真要隔离,应该用依赖注入容器控制实例化时机,而不是指望 autoloader “看不见”
自动加载只是映射关系,不加载 ≠ 不存在。真正该拦住的,是调用链本身。










