执行 composer install --no-dev 后,需验证 vendor/ 下无 dev 包目录(如 vendor/phpunit/phpunit)、composer show phpunit/phpunit 返回“Package not found”,且 class_exists('PHPUnit\Framework\TestCase') 为 false,才能确认 dev 依赖真正未安装且未被 autoload。

composer install --no-dev 后怎么确认 dev 依赖真没装?
执行 composer install --no-dev 后,不能只看命令输出“Skipping”,得验证结果是否真实生效。
最直接的方法是检查 vendor/ 目录下是否存在对应包的文件夹:
- 若
vendor/phpunit/phpunit这类典型require-dev包目录不存在,说明跳过成功 - 若存在,说明要么命令没加
--no-dev,要么composer.lock里仍保留着该包(上一次 install 没带参数) - 运行
composer show phpunit/phpunit,返回Package not found才算真正未安装
注意:composer.json 里有 require-dev 条目 ≠ 运行时会装它;是否装,只取决于本次 install 或 update 是否带 --no-dev 参数。
如何验证生产环境 autoload 不含 dev 类?
即使 vendor/ 里没装 dev 包,如果项目代码里写了 use PHPUnitFrameworkTestCase 并被自动加载器扫描到,仍可能在运行时报错——但前提是这个类已被加载进 autoloader。
关键判断点是:运行 composer dump-autoload --no-dev -o 后,检查生成的 vendor/autoload.php 是否还包含 autoload-dev 相关路径。更稳妥的做法是临时加一行代码:
var_dump(class_exists('PHPUnitFrameworkTestCase'));
在生产环境执行,返回 false 才说明 autoload 层面已隔离干净。
常见疏漏:
-
autoload-dev的 PSR-4 映射路径被误写进autoload(主 autoload 块),导致 dev 类始终可加载 - 某些框架(如 Laravel)的
phpunit.xml或测试引导文件被意外引入生产入口 - 用了
files类型 autoload 加载了全局函数文件,而该文件在 dev 包里且未被排除
composer show -t 显示的依赖树能反映当前环境吗?
不能。composer show -t 展示的是 composer.lock 中记录的**完整依赖关系图**,不管你是用 --no-dev 还是全量安装,它都照常显示所有 require 和 require-dev 的传递依赖。
它适合查“为什么装了 X”,不适合查“现在有没有 X”。例如:
-
composer show -t | grep phpunit可能搜出十几行,哪怕你刚用--no-dev装完 - 真正反映当前安装状态的命令是
composer show(不带参数),它只列出已安装的包 - 想确认某包是否被间接拉入,用
composer depends vendor/package,但它只查 direct/indirect require 关系,不区分 dev 或 prod
所以别依赖 -t 判断环境隔离效果,它只是结构快照,不是运行时视图。
CI/CD 中怎么防住 --no-dev 漏掉?
最容易出问题的地方是 CI 脚本写成 composer install 硬编码,没根据 $ENV 动态加参数。
推荐做法:
- Dockerfile 中明确写死:
RUN composer install --no-dev --optimize-autoloader --no-interaction - GitHub Actions 或 GitLab CI 中用条件判断:
if: ${{ env.NODE_ENV == 'production' }}控制是否加--no-dev - 部署前加一道校验脚本:
! ls vendor/phpunit 2>/dev/null,失败即中止发布
还有一个隐藏坑:某些共享主机或 PaaS 平台(如 Laravel Forge)默认启用 “auto-install dev dependencies” 开关,需手动关闭——这比写错命令更难排查。


















