生产环境执行 composer install 必须加 --no-dev,否则会安装 require-dev 包导致 Class not found 等错误;若仍装入 dev 包,根本原因是 composer.lock 文件残留 dev 记录,需先运行 composer update --no-dev --lock 更新 lock 文件,再用 composer install --no-dev --optimize-autoloader 部署。

生产环境执行 composer install 必须加 --no-dev,否则大概率会报 Class not found、vendor/bin/phpunit: not found 或直接 500 错误——这不是“可能”,而是部署失败的常见起点。
为什么加了 --no-dev 还是装了 dev 包?
根本原因不是参数没加对,而是 composer.lock 文件本身“记错了”。composer install 只照 lock 文件装,不验证 require-dev 是否该存在。
- 如果 lock 文件是上次用
composer update(没加--no-dev)生成的,里面就存着phpunit/phpunit、laravel/pint等包的版本记录 - 此时执行
composer install --no-dev,Composer 会跳过 autoload-dev 和 @dev 脚本,但不会删掉 lock 里已有的 dev 包——它照装 - 典型现象:
friendsofphp/php-cs-fixer依然出现在vendor/里,体积多出 30–50MB,部署超时
正确做法:在 CI 或本地干净环境中先运行 composer update --no-dev --lock,提交新 lock;后续所有部署都只用 composer install --no-dev --optimize-autoloader。
composer install --no-dev --optimize-autoloader 到底做了什么?
这三个参数不是可选组合,而是一体动作。漏一个,就可能埋下线上隐患。
-
--no-dev:跳过require-dev中所有包及其传递依赖(比如phpunit带的sebastian/exporter)、跳过autoload-dev命名空间(如"Tests\": "tests/"不注册)、跳过标记为@dev的 scripts(如post-autoload-dump里的phpstan) -
--optimize-autoloader:生成vendor/composer/autoload_classmap.php静态映射,绕过 PSR-4 文件系统查找,实测可减少 10–20% 请求耗时;没有它,--no-dev的收益大打折扣 - 二者必须同时出现:只加
--no-dev会留一堆无用文件;只加--optimize-autoloader会让 autoload 更快,但 dev 类仍可能被意外加载(尤其当代码里写了new TestsFooTest())
能不能在生产服务器上直接跑 composer install?
不推荐,多数情况下不该这么做。
- 生产机通常没装 Composer,也不该给 web 用户写权限;更关键的是,
install会触发post-autoload-dump等脚本,可能暴露路径、调用缺失扩展(如 xdebug)、或因内存不足(memory_limit=128M)直接中断 - 若真要在线安装,必须确保:
COMPOSER_HOME指向可写目录;php.ini中memory_limit ≥ 1536M;且php -m | grep openssl返回非空(否则 HTTPS 包下载失败) - 最佳实践:在 CI 或本地 Docker 环境中执行完整命令,把整个
vendor/打包上传;bootstrap/autoload.php必须引用vendor/autoload.php(标准 Laravel 默认如此),而非vendor/autoload-dev.php
APP_ENV=production 或 APP_DEBUG=true 会影响 Composer 吗?
完全不影响。Composer 不读 .env,它只认 composer.json 和 composer.lock。
但这两个变量会间接暴露安装是否干净:
- 如果漏了
--no-dev,而APP_DEBUG=true,Laravel 启动时可能尝试加载vendor/autoload-dev.php,直接 500 报错 -
APP_ENV=production会禁用调试工具栏,但不会掩盖Class 'PHPUnitFrameworkTestCase' not found这类错误——你看到的仍是清晰异常,不是“页面空白” - 真正要检查的是:部署后运行
php artisan tinker,输入class_exists('TestsTestCase'),返回false才算过关
复杂点在于,config.platform 设置容易被忽略:本地 PHP 是 8.2,生产是 8.1,就得在 composer.json 显式写 "platform": {"php": "8.1"},否则 install 可能拉错兼容版本——这和 --no-dev 无关,但同样致命。


















