autoload-dev是独立于autoload的开发专用加载通道,必须作为composer.json顶层字段配置,键名严格为“autoload-dev”,拼写错误或嵌套即被静默忽略;修改后须执行composer dump-autoload --dev才生效,否则类无法加载。

autoload-dev 不是 autoload 的子集,而是独立通道
Composer 只认顶层键名 autoload-dev,拼错、缩进错、嵌套进 require-dev 或其他字段里,整个配置都会被静默忽略。它和 autoload 是并列关系,不是补充——混进去的测试映射,composer install --no-dev 也拦不住。
常见错误现象:Class MockeryMockInterface not found 线上报错,但你根本没装 mockery;实际是 autoload-dev 配错了位置,导致它的命名空间被写进了生产环境的 vendor/autoload.php。
-
autoload-dev必须写在composer.json根层级,和autoload同级 - 键名必须是
autoload-dev(全小写,带连字符),不能是autoloadDev或autoloader-dev - 修改后不运行命令 = 白改;Composer 不监听 JSON 变更
测试类路径和命名空间必须严格对齐
把 tests/Unit/ExampleTest.php 映射到 "Tests\": "tests/",文件里就必须写 namespace TestsUnit;。末尾反斜杠可加可不加,但推荐统一用 "Tests\"(注意转义),否则 Composer 解析失败。
绝对不要这样写:"App\Tests\": "tests/"。这会让测试类和生产命名空间耦合,一旦生产代码里不小心 use AppTestsSomething,--no-dev 就失效了。
- 路径必须真实存在,Composer 不校验,但 phpunit 找不到类时只会静默失败
- 命名空间不能和
autoload中的重叠,比如"App\": "src/"和"App\Tests\": "tests/"是危险组合 - 测试类别被生产代码引用——这是设计泄漏,比配置错误更致命
手动刷新 autoload-dev 必须加 --dev 参数
composer dump-autoload 默认只处理 autoload,完全不碰 autoload-dev。这是最常踩的坑:改完配置、执行 dump 命令、发现 phpunit 还是报错——因为你没加 --dev。
验证是否生效:运行 composer dump-autoload --dev 后,打开 vendor/autoload.php 搜索 Tests\,看是否存在对应注册;再运行 composer install --no-dev,检查 vendor/composer/autoload_psr4.php 是否还包含 "Tests\" 键。
- CI 构建脚本若用了
composer install --no-dev,本地却没加--dev,就会出现“本地通、CI 报错” -
autoload-dev中的files列表只在开发环境被require_once,别放有副作用的初始化逻辑 - 如果用了
classmap模式,路径必须指向具体目录或文件,不能是通配符
exclude-from-classmap 对 tests/ 完全无效
exclude-from-classmap 只影响 classmap 生成阶段,对 psr-4 加载器毫无作用。哪怕你在 composer.json 里写了 "exclude-from-classmap": ["tests/"],只要 autoload 里声明了 "Tests\": "tests/",运行时照样会去 tests/ 下扫描文件,触发磁盘 I/O。
真正起效的方式只有一个:把所有测试相关配置全挪到 autoload-dev,并确保部署时强制加 --no-dev。其余所有“排除”手段都是补救,不是替代。
-
exclude-from-classmap应该用在 classmap 场景下,比如排除废弃的LegacyHelper.php或零散的bootstrap.php - 它必须写在
composer.json根级,值为相对路径数组,不支持通配符 - tests/ 下混放大量非 PHP 文件(截图、日志、.md)会拖慢
dump-autoload速度,尤其在 CI 挂载网络存储时
最稳妥的做法不是靠“排除”,而是让测试代码从一开始就不进入生产自动加载的视野——路径隔离、命名空间隔离、安装参数隔离,三者缺一不可。任何一步漏掉,都可能在线上某个深夜触发一个意想不到的 Fatal error。











