autoload.exclude 仅在 composer 5.0+ 生效,且仅作用于 psr-4/psr-0 路径扫描,对 classmap 和 files 无效;exclude-from-classmap 仅在显式声明 classmap 时起作用;最稳妥的排除方式是不将其纳入任何 autoload 路径。

autoload.exclude 在 Composer 5.0+ 才生效,低版本写它等于白写
如果你的 composer --version 输出低于 5.0.0(比如仍是 2.x 或 4.x),那 autoload.exclude 字段会被解析器直接跳过——不是配置格式错,是压根不认。它只作用于 psr-4 和 psr-0 映射路径下的文件扫描,对 classmap 和 files 类型完全无效。
常见误配:把 "exclude": ["tests/Stub/"] 写进 composer.json,但项目用的是 Composer 4.4,结果发现 tests/Stub/ExampleStub.php 还是能被 new AppTestStubExampleStub() 加载成功。
- 确认版本:
composer --version,必须 ≥ 5.0.0 - 路径必须相对项目根目录,写成
"tests/Stub/"✅,不能是"./tests/Stub/"或"tests/Stub"(后者可能意外匹配tests/Stub.php) - 改完必须运行
composer dump-autoload,否则vendor/autoload.php不更新
exclude-from-classmap 只在显式声明 classmap 时起作用
exclude-from-classmap 不是全局黑名单,它只在 composer.json 里明确写了 "classmap": [...] 的前提下,才参与 dump-autoload --optimize 阶段的路径过滤。纯 psr-4 项目加了它,等于没写。
例如你写了:"autoload": { "psr-4": {"App": "src/"}, "exclude-from-classmap": ["tests/"] }
——这不会让 tests/ 里的类消失,因为 tests/ 根本没在 classmap 列表里被扫描。
- 正确用法:先写
"classmap": ["src/", "lib/"],再配"exclude-from-classmap": ["lib/TestHelpers.php", "lib/legacy/"] - 路径区分大小写,
"lib/legacy/"≠"lib/Legacy/" - 支持
*(如"legacy/*"),但不支持**;目录末尾斜杠推荐加上,避免误排除同名文件 - 运行后务必检查
vendor/composer/autoload_classmap.php,确认对应条目是否真被删掉
真正跳过 tests/examples/docs 的最稳妥做法:别把它放进 autoload
Composer 没有“排除”机制,只有“白名单式声明”。想让某个目录不进自动加载器,最干净的办法是——根本不要把它写进 autoload 或 autoload-dev 的任何路径里。
错误写法:"psr-4": {"": "src/"} + 把 docs/ 放在 src/ 下 → 所有 .php 文件(哪怕只是模板脚本)都会被 PSR-4 扫描到。
- 正确姿势:把
tests/、examples/、docs/移出所有autoload路径;必须共存时,统一收进autoload-dev(它们只在--dev模式下注册) - 工具脚本(如
build.php)若不想被加载,确保不含class、interface或trait声明,且不以.php结尾(或改后缀) - 运行
composer dump-autoload -v观察输出,如果反复进入node_modules/、.git/等目录,说明你的 autoload 路径太宽,或项目根目录混入了不该有的.php文件
运行时动态加路径?小心 classmap-authoritative 和 OPcache
你可以用 $loader->addPsr4('Test\', __DIR__ . '/tests/stubs/') 在 require 'vendor/autoload.php' 后追加规则,但这只影响当前 PHP 进程,且极易踩坑。
-
addPsr4()第二个参数必须是绝对路径,'tests/stubs/'❌,__DIR__ . '/tests/stubs/'✅ - 命名空间末尾必须带反斜杠:
'Test\'✅,'Test'或'Test/'❌ - 启用
--classmap-authoritative后,所有动态添加的 PSR-4 规则会被忽略——它只认autoload_classmap.php里的条目 - Swoole / PHP-FPM 常驻进程里,改了 autoload 规则必须重启 worker;OPcache 启用时,还得调
opcache_reset(),否则旧判断仍缓存
动态加载适合单元测试 stub、CLI 插件扫描这类临时场景,不适合主业务逻辑——那些必须走 composer.json + dump-autoload 流程,否则 IDE 补全和部署一致性都成问题。











