composer install 装 tests 依赖是因为 require-dev 中的测试包(如 phpunit)未加 --no-dev;生产环境必须用 composer install --no-dev --optimize-autoloader;设 "config": {"dev": false} 可全局禁用 dev 包安装。

composer install 为什么还装了 tests 目录下的依赖
因为 composer install 默认读 composer.json 的全部 require 和 require-dev,而很多测试插件(比如 phpunit/phpunit、mockery/mockery)被写在 require-dev 里——它不是“可选”,而是“开发时必须”。生产环境跑 install 却没加 --no-dev,这些包照装不误。
常见错误现象:vendor/ 里出现 phpunit/、sebastian/、symfony/var-dumper(调试用),甚至整个 tests/ 目录被某些插件自动复制进来。
- 上线部署务必加
--no-dev:composer install --no-dev --optimize-autoloader -
--optimize-autoloader不只是提速,还会剔除未声明的类自动加载规则(比如测试类路径) - CI/CD 脚本里漏掉
--no-dev是高频翻车点,尤其 Jenkins 或 GitHub Actions 中手动写命令时
怎么让 composer 永远不装 dev 包(哪怕本地开发)
这不是常规需求,但真有场景:比如你维护一个只供其他项目 require 的 SDK,自己不写测试,也不希望同事误装 dev 依赖污染 vendor。这时靠配置比靠每次敲参数更可靠。
核心是改 composer.json 的 config 段:
{
"config": {
"platform-check": false,
"preferred-install": "dist",
"sort-packages": true,
"discard-changes": true,
"allow-plugins": {
"phpstan/extension-installer": true
}
}
}
上面没用——真正起作用的是这个:
- 加
"dev": false到config:"config": { "dev": false } - 该设置会让所有
composer install和composer update自动忽略require-dev,等价于永远带--no-dev - 注意:它不影响
composer require --dev写入 JSON,只是不执行安装;想临时装 dev 包得显式加--dev
排除特定测试插件(比如 phpunit),但保留其他 dev 依赖
没法直接“排除某个包”,composer 没提供 --exclude 这种开关。但可以绕过:把不想进生产的包从 require-dev 移到 require 下的 provide 或用脚本清理。
更实际的做法是“分组管理”:
- 用
composer require --dev --no-install phpunit/phpunit先写入但不装 - 再通过
scripts在post-install-cmd里删掉它:"rm -rf vendor/phpunit"(Linux/macOS)或rd /s /q vendor\phpunit(Windows) - 或者改用
composer create-project搭配自定义installer-paths,把测试类路径指向/dev/null(不推荐,太 hack)
真正稳的方式:别把它放 require-dev。测试工具应由 CI 环境单独装,而不是塞进项目依赖树。
为什么 vendor/bin/phpunit 还在,即使用了 --no-dev
因为 vendor/bin/ 下的可执行文件是软链接或包装脚本,由 composer 根据 bin 字段自动生成,和是否安装包无关。只要 composer.json 里写了 "bin": ["phpunit"](哪怕在 require-dev 包里),install 阶段就会创建链接。
这会导致两个问题:一是链接指向不存在的 target(报 Command not found),二是上线后残留无用入口。
- 检查
vendor/bin/下每个文件的 target:ls -l vendor/bin/phpunit - 如果 target 是
../phpunit/phpunit/phpunit但phpunit/目录不存在,说明它只是个空壳 - 上线前加一步清理:
find vendor/bin -type l ! -exec test -e {} ; -delete(删失效链接)
最干净的解法是:别让测试工具出现在项目自己的 composer.json 里,交给 CI 配置或全局安装。










