生产环境必须用 composer install --no-dev,否则会混入phpunit等dev包引发安全与性能问题;需搭配--optimize-autoloader、--classmap-authoritative、--no-interaction等参数,并确保composer.lock纯净。

生产环境必须用 composer install --no-dev,否则 vendor 里大概率混进 phpunit、phpstan、debugbar 这类包——不是功能错,是安全风险和性能拖累。
为什么 composer install 默认会装 dev 包?
Composer 不区分“当前是不是生产环境”,它只看 composer.json 里有没有 require-dev,以及你有没有显式告诉它“别装”。没加 --no-dev,它就照单全收。哪怕你只部署一个 API,symfony/var-dumper 或 barryvdh/laravel-debugbar 也会被拉进来,可能意外启用、暴露调试信息,或因 autoload 冲突导致 Class not found。
-
require-dev是声明,不是开关;删掉它才能彻底消失,但开发时又需要——所以靠参数控制才是正路 - 某些框架(如 Laravel)的 Service Provider 里会条件加载 dev 工具,若没做
class_exists判断,--no-dev后反而报错 -
autoload-dev规则不会生效,但如果你代码里硬写了new TestsFooTest(),运行时仍会崩
composer install --no-dev 必须搭配哪些参数?
光加 --no-dev 不够,常见组合缺一不可:
-
--optimize-autoloader:生成扁平类映射,避免每次请求都遍历文件系统找 class -
--classmap-authoritative:告诉 autoloader “类只在 classmap 里,别去 PSR-4/PSR-0 目录猜了”,进一步提速 -
--no-interaction:CI/CD 或 Docker 构建时无 TTY,不加这个可能卡在交互提示上等超时 -
--ignore-platform-reqs:仅限临时调试,比如构建机没装ext-gd,但生产镜像必须提前装好扩展
推荐完整命令:composer install --no-dev --optimize-autoloader --classmap-authoritative --no-interaction
同步前最容易忽略的 lock 文件问题
composer.lock 里存着 require-dev 的版本记录,但 --no-dev 只跳过安装,不跳过解析。如果 lock 文件来自开发分支、含大量旧版 dev 包,可能导致主依赖降级或冲突。
- 上线构建前先跑一次:
composer update --no-dev -o,强制刷新 lock 中 production 部分 - 检查 lock 是否干净:
grep -q '"require-dev"' composer.lock && echo "warning: dev section exists" || echo "clean" - Git 提交前确认
composer.lock在暂存区,否则 CI 拉的是旧 lock,--no-dev也救不了 - Docker 构建时,
COPY composer.json composer.lock ./后立刻composer install --no-dev -o,中间别执行其他 composer 命令
验证是否真没装 dev 包
别只信命令,上线后快速确认:
- 执行:
composer show --dev,应返回空或提示 “no packages” - 查目录:
ls vendor/ | grep -E "(phpunit|phpstan|mockery|symfony/debug|barryvdh)",有输出就是漏了 - 看 autoload:
grep -r "Tests\" vendor/autoload.php,若有匹配,说明 autoload-dev 规则被误载(极少见,但发生过)
最麻烦的情况不是没加 --no-dev,而是加了却用了脏 lock 或平台配置不一致——PHP 版本、扩展缺失、config.platform 写错,都会让 Composer 在跳过 dev 的同时,把 require 里的包也装错版本。











