composer install 默认安装 dev 依赖是因为读取 composer.lock 中记录的全部包,包括 require-dev 下的,以保证环境可重现;生产环境应使用 --no-dev(等价于 --production)跳过安装,并配合 composer dump-autoload --no-dev 清理 autoload 映射。

composer install 为什么默认装了 dev 依赖?
因为 composer install 默认读取 composer.lock 中记录的全部包,包括 require-dev 下的。哪怕你本地没写 --no-dev,只要 lock 文件里存了 dev 包,它就照装不误——这是为了保证可重现性,不是 bug。
常见错误现象:composer install 在线上服务器跑完,发现 phpunit、fakerphp/faker 这类包也进了 vendor/,既浪费磁盘又可能引入安全风险。
- 使用场景:部署到生产环境(如 CI/CD 的 build 阶段、Docker 构建、线上服务器手动部署)
- 开发机上不需要加
--no-dev,否则phpstan或psalm就跑不了 - 如果项目没生成过
composer.lock,--no-dev会按composer.json的require部分解析依赖,跳过require-dev
--no-dev 和 --production 有啥区别?
--production 是 --no-dev 的别名,两者完全等价。Composer 从 2.0 开始就明确文档写了:--production 只是兼容旧脚本的 alias,内部逻辑一模一样。
容易踩的坑:--prod 这个缩写并不存在,输错会报错 Unrecognized option: --prod;另外,--no-dev 不影响 autoloading 规则,不会删掉 autoload-dev 里的命名空间映射,只是不装那些包。
- 参数差异:
--no-dev(推荐用这个)、--production(可用,但语义不如前者直白) - 性能影响:略快一点点,因为少解析和下载几十个包,但主要收益在体积和安全性
- 兼容性:所有 Composer 1.x 和 2.x 都支持,无版本顾虑
Docker 构建时怎么安全地跳过 dev 依赖?
关键点:不能只靠 RUN composer install --no-dev,得确保构建上下文里没有 composer.lock 的 dev 包残留,也不能让缓存把上一次带 dev 的安装结果复用进来。
实操建议:
- 在
Dockerfile里显式加--no-dev,别指望基础镜像默认关掉 dev - 用多阶段构建时,build 阶段可以装 full 依赖做测试,final 阶段只
COPY --from=builder /app/vendor /app/vendor并确保 builder 阶段用了--no-dev - 如果用
composer install前删了composer.lock,那必须加--no-dev,否则会退化成composer update行为,且可能装错版本
为什么 vendor/autoload.php 还能加载 dev 类?
因为 --no-dev 只控制「是否安装」,不控制「是否注册自动加载」。autoload-dev 里的 PSR-4 映射仍会写进生成的 vendor/autoload.php,只是对应目录根本不存在——运行时遇到 class not found 才真正报错。
这导致一个隐蔽问题:某些静态分析工具或 IDE 会基于 autoload 文件推测类存在,给出错误补全或不报未定义类警告。
- 解决办法:上线前用
composer dump-autoload --no-dev,它会跳过autoload-dev段生成 autoload 文件 - 注意:这个命令必须在
--no-dev安装之后执行,否则--no-dev的效果被 autoload 映射抵消 - CI/CD 中建议链式执行:
composer install --no-dev && composer dump-autoload --no-dev
Faker\Factory::create() 看似没报错,直到 runtime 才崩。










