生产环境必须用 composer install --no-dev --optimize-autoloader,跳过 require-dev 包安装并优化自动加载;composer.lock 必须提交且与 install 配合使用;config.platform 应锁死 PHP 及扩展版本,确保依赖兼容。

生产环境必须用 composer install --no-dev,否则会把 phpunit、larastan 甚至 barryvdh/laravel-debugbar 这类开发工具装上去——不是“可能”,是大概率发生,且常伴随安全告警和性能抖动。
为什么 composer install --no-dev 是生产部署底线
这个参数只跳过 require-dev 里的包安装,不删配置、不改 autoload-dev、不影响 composer.lock 结构。它解决的是「不该装的别装」,而不是「装了但禁用」。
- 漏加
--no-dev是线上事故高频原因,尤其在 Laravel/Symfony 项目里,symfony/debug被启用后可能暴露堆栈或敏感路径 -
composer install --no-dev --optimize-autoloader应作为生产构建默认组合:前者裁剪依赖,后者压缩自动加载映射,减少 PHP 启动时的文件扫描开销 - CI/CD 流水线脚本里写死该命令,Dockerfile 的
RUN指令也必须带上,不能依赖环境变量临时覆盖
composer.lock 必须提交,且不能被选择性忽略
composer.lock 不是缓存文件,它是依赖图的快照。它记录的不只是你直接 require 的包版本,还包括所有嵌套子依赖(比如 monolog 依赖的 psr/log 具体是 1.1.4 还是 1.2.0)。
- 不提交
composer.lock→ 每个开发者本地composer install解析出的版本都可能不同 → 「在我机器上能跑」成为常态 - CI 和生产环境必须用
composer install(非update),否则 lock 文件形同虚设 - 修改
composer.json后,必须运行composer update生成新 lock 并一起提交;只改autoload或scripts字段则无需更新 lock
PHP 版本不一致?靠 config.platform 锁定,不是靠人盯
开发机是 PHP 8.3,但生产服务器还在跑 8.1 —— 这种情况不用降级本地环境,也不该在 CI 里用 --ignore-platform-reqs 硬扛。正确做法是在 composer.json 里声明目标平台:
"config": {
"platform": {
"php": "8.1.0",
"ext-gd": "8.1.0",
"ext-mbstring": "8.1.0"
}
}
-
platform.php必须写死完整版本号(如"8.1.0"),写"^8.1"或"~8.1"无效 - 该配置影响依赖解析阶段:Composer 会过滤掉要求 PHP >=8.2 的包,避免装上后 runtime 报错
- 搭配
platform-check: true可在install时校验当前环境是否满足 platform 声明,失败则中止
autoload-dev 失效 ≠ 代码报错,但硬引用就崩
用了 --no-dev,require-dev 里的包不装,连带它们定义的 autoload-dev 规则也失效。但这本身不会导致错误——除非你的业务代码里写了 new \Tests\FooTest() 或直接 include 'tests/Helper.php'。
- 检查所有
require-dev包是否仅用于 CLI 工具(如 PHPUnit)、静态分析(PHPStan)、或开发时的调试逻辑 - 若测试类被业务代码引用,说明架构已混淆,应剥离或重构为正式依赖
- CI 中仍需完整安装(不加
--no-dev),否则测试根本跑不起来
最易被忽略的点:platform 配置和 --no-dev 是两件事,一个管「能不能装」,一个管「装不装」。两者要同时生效,才真正守住环境一致性边界。


















