生产环境必须用 composer install --no-dev,但其生效前提是 composer.lock 文件中未记录 dev 包;若 lock 文件已含 phpunit 等 dev 依赖,则 --no-dev 无效且会报错。

生产环境必须用 composer install --no-dev,但光加参数没用
它不是开关,而是约束条件:只在 composer.lock 文件里**没记录 dev 包**的前提下才真正生效。如果 lock 文件本身含 phpunit/phpunit 或 friendsofphp/php-cs-fixer,那 --no-dev 就只是个摆设——install 会报错“dev dependencies not found”,因为 Composer 想装却被告知不准装。
常见错误现象:
- 执行
composer install --no-dev后,vendor/里还是有phpunit——说明上次composer update没带--no-dev,lock 文件已污染 - CI 部署成功,但线上报
Class 'Tests\FooTest' not found——autoload-dev仍注册了"Tests": "tests/",而某处硬编码加载了测试类 -
composer.lock是 Windows 下生成的,部署到 Linux 服务器后部分包安装失败——平台差异导致依赖解析偏移
实操建议:
- 首次上线前,在干净环境(无
vendor/、无 lock)运行:composer update --no-dev --lock,再提交composer.lock - CI/CD 脚本中,先
git clean -xffd vendor/清掉残留,再跑composer install --no-dev --prefer-dist --optimize-autoloader --no-scripts - 验证是否生效:部署后进容器或服务器,执行
composer show,确认列表里没有phpunit、phpstan、symfony/debug-bundle
--no-dev 和 --production 有啥区别?别输 --prod
两者完全等价,--production 是 --no-dev 的别名,Composer 2.0+ 文档明确写了这是为了兼容旧脚本。但注意:--prod 这个缩写根本不存在,输进去会报错 Unrecognized option: --prod。
参数差异:
-
--no-dev:语义清晰,推荐日常使用 -
--production:可读性稍弱,但 CI 脚本里若已有历史写法,不必强行改 -
--no-dev不影响autoload-dev的路径注册——它只跳过安装,不删映射;所以即使没装phpunit,只要vendor/autoload.php里还保留着测试路径,class_exists('Tests\FooTest')仍可能返回true
性能影响很小,主要收益在体积和安全性:少装二三十个包,vendor/ 小 10–30MB,启动快一点,攻击面也窄一点。
Docker 构建时,--no-dev 容易被缓存绕过
很多 Dockerfile 写成这样:RUN composer install --no-dev,看起来没问题,但实际构建时可能复用了上一次带 dev 包的 layer 缓存,导致 vendor/ 里悄悄混入 php-cs-fixer 或 symfony/var-dumper。
实操建议:
- 在
RUN前加清理:RUN rm -rf vendor/ && composer install --no-dev --prefer-dist --optimize-autoloader - 用多阶段构建:build 阶段装全量依赖跑测试,final 阶段只
COPY --from=builder /app/vendor /app/vendor,且确保 builder 阶段命令带--no-dev - 避免在基础镜像里预装 Composer 依赖——不同项目对 dev 包需求不同,预装等于埋雷
兼容性没问题:--no-dev 在 Composer 1.x 和 2.x 全支持,不用纠结版本。
为什么 vendor/autoload.php 还能加载开发类?
因为 --no-dev 只控制「是否安装包」,不控制「是否注册自动加载规则」。autoload-dev 是 composer.json 里的独立配置项,它的路径映射默认仍会写进 vendor/autoload.php,哪怕对应包一个都没装。
典型错误场景:
- 本地开发时写了
dump($data),依赖symfony/var-dumper,但它在require-dev里——上线后报Class 'Symfony\Component\VarDumper\VarDumper' not found - CI 脚本里有一行
require_once 'tests/bootstrap.php',而bootstrap.php又 require 了PHPUnit\Framework\TestCase,但phpunit没装
解决办法只有两个:
- 把真被业务代码引用的包(比如
symfony/var-dumper)从require-dev移到require——别靠字段“自我安慰” - 部署后手动运行:
composer dump-autoload --no-dev,强制删掉autoload-dev的路径映射(注意:这不会删已存在的类文件,只改 autoload.php)
真正容易被忽略的是锁文件的“信任链”:它不像代码那样改了就生效,而是由生成它的那条命令决定内容。只要 composer.lock 里有 dev 包,你就得重跑一次合规的 update --no-dev --lock,否则所有后续操作都是在补漏。










