composer install --no-dev是唯一正解,它硬性跳过require-dev包及其传递依赖、autoload-dev命名空间和@dev脚本,必须配合--optimize-autoloader与--classmap-authoritative使用,且依赖干净的composer.lock文件。

生产环境必须加 --no-dev,否则会装 PHPUnit、PHPStan、xdebug 等包——这不是“建议”,是部署失败的常见原因。
为什么 composer install 默认会装测试依赖?
Composer 不知道你是不是在生产环境。它只认 composer.json 里写的什么就装什么:require 和 require-dev 全部照单全收。你没加 --no-dev,barryvdh/laravel-debugbar 就真会被解压进 vendor/,还可能因 PHP 版本不兼容直接报错。
常见错误现象包括:
-
vendor/体积暴涨 30–50MB,CI 构建超时 - 线上报
Class 'PHPUnitFrameworkTestCase' not found(说明业务代码误引用了 dev 类) - Docker 镜像启动变慢,甚至暴露
/_profiler或/vendor/phpunit入口
--no-dev 到底跳过哪些东西?
它不只是删掉 require-dev 列表里的包,而是一整套连锁过滤:
- 跳过
require-dev中所有包及其传递依赖(比如你装了php-cs-fixer,它带的symfony/console也不会进vendor) - 跳过
autoload-dev配置——那些测试用的 PSR-4 命名空间(如"Tests\": "tests/")不会注册进 autoloader - 跳过
scripts中标记为@dev的钩子,比如post-autoload-dump里调的phpstan就静默跳过
注意:--no-dev 不影响 autoload(非 dev)规则的加载,也不改变已安装包的行为——它只控制“装不装”和“映射不映射”。
为什么加了 --no-dev 还是装了 dev 包?
因为 composer.lock 文件本身“记错了”。--no-dev 只在 lock 文件已按生产规则生成的前提下才生效。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
典型现象:执行 composer install --no-dev 后,friendsofphp/php-cs-fixer 依然出现在 vendor/ 里。
真正原因:composer.lock 是上次用 composer update(没加 --no-dev)生成的,里面已经存了 dev 包的版本记录;install 只是照 lock 装,--no-dev 此时被忽略。
正确做法:
- 在 CI 构建阶段,先运行
composer update --no-dev --lock(不是install),生成不含 dev 元数据的 lock 文件 - 确认新
composer.lock里没有require-dev键,且packages数组明显变短 - 再执行
composer install --no-dev --optimize-autoloader --classmap-authoritative
最容易被忽略的一点:autoload 优化不能只靠 -o
composer dump-autoload -o 本身对纯 PSR-4 项目(如 Laravel 默认结构)几乎无效——它只生成 classmap,但现代 Composer 2+ 默认启用更优的 --classmap-authoritative 模式。
真正有效的组合是:
-
composer install --no-dev(剔除包) -
--optimize-autoloader(等价于-o,合并映射) -
--classmap-authoritative(强制只从 classmap 查找,彻底跳过磁盘扫描)
漏掉最后一个,autoloader 仍会 fallback 到 PSR-4 路径扫描,性能提升微乎其微。而且,如果 opcache 没开,前面所有优化都白搭。

















