生产部署必须加 --no-dev,镜像加速不改变这个规则;中文镜像仅加速包下载,不干预依赖解析与安装逻辑,--no-dev 才能跳过 require-dev 中的 phpunit 等非生产依赖,避免线上报错、体积膨胀和安全风险。

生产部署必须加 --no-dev,镜像加速不改变这个规则
中文镜像(如阿里云、腾讯云、华为云 Composer 镜像)只加速包下载,不干预依赖解析和安装逻辑。哪怕你用的是 https://mirrors.aliyun.com/composer/,composer install 依然默认装 require-dev 里的所有包——包括 phpunit/phpunit、symfony/debug-bundle、laravel-debugbar。
常见错误现象:
- 线上报
Fatal error: Call to undefined function xdebug_is_enabled(),但代码里根本没调用它——因为symfony/debug被装了,且框架启动时无条件加载 - Docker 镜像体积多出 180MB,
vendor/phpunit/和vendor/php-cs-fixer/全在生产环境里 - 安全扫描发现
roave/security-advisories失效,根源是require-dev引入了间接依赖链
解决方案很简单:不管用哪个镜像,只要上线就加参数:
composer install --no-dev --optimize-autoloader- Dockerfile 中写死:
RUN composer install --no-dev --optimize-autoloader - GitHub Actions 里别写
composer install,必须写全参数
config.platform 是解决“本地能装、线上报错”的唯一靠谱方式
中文镜像不会掩盖 PHP 版本或扩展差异。比如你本地 PHP 8.2 有 ext-xdebug,线上是 PHP 8.1 且没装 ext-xdebug,Composer 可能因依赖声明(如某包要求 "ext-xdebug": "^3.1")直接拒绝安装,或装上后运行时报 Call to undefined function xdebug_is_enabled()。
这时不能靠换镜像,得靠 config.platform 告诉 Composer:“假装目标环境是这样”。在 composer.json 里写:
"config": {
"platform": {
"php": "8.1.0",
"ext-gd": "8.1.0",
"ext-xdebug": "3.1.5"
}
}
注意:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 版本号必须是具体值,
"php": "^8.1"或"~8.1"会被忽略 - 它只影响依赖解析阶段(即选哪些包能装),不解决运行时缺失扩展的问题——真实没装
ext-gd,imagecreate()还是崩 - 上线构建更干净的做法是加
COMPOSER_PLATFORM_CHECK=0 composer install --no-dev,比改platform更可控
autoload-dev 和 --no-dev 不是一回事,硬引用会直接崩
--no-dev 只跳过安装 require-dev 里的包,但 autoload-dev 的 PSR-4 规则默认仍被写入 vendor/autoload.php。如果你在控制器里写了 new \Tests\FooTest() 或 dump($data)(依赖 symfony/var-dumper),而它又只在 require-dev 里,那运行时就是 Class not found。
关键点:
-
autoload-dev是自动加载路径声明,不是“是否启用”开关 -
--no-dev不自动禁用autoload-dev映射——除非你额外跑composer dump-autoload --no-dev - 如果某个包既是开发工具又是运行时需要(比如
symfony/var-dumper用于日志调试),就不能只放require-dev,得挪到require并配运行时判断 - CI 报
Class 'PHPUnit\Framework\TestCase' not found,大概率是缓存复用了上一次--no-dev的vendor/,而不是镜像问题
别搞多个 composer.json,中文镜像下更容易出锁文件冲突
有人想用 composer.prod.json + 脚本合并来“适配环境”,这在中文镜像下尤其危险:不同镜像源的包元数据可能略有差异,合并后生成的 composer.lock 在本地和 CI 上解析结果不一致,导致“在我机器上能跑、线上崩”。
Composer 不支持多配置文件切换,composer.json 是静态文件,无法写 if env === 'prod'。
真正可靠的做法只有三个:
- 把运行时必需的包全放
require,开发工具放require-dev - 部署命令始终带
--no-dev(Docker、CI、手动部署都一样) - 环境差异逻辑(数据库配置、缓存驱动、日志级别)全部挪到 PHP 运行时,读
$_ENV['APP_ENV']或getenv('APP_ENV')判断
镜像只是下载通道,真正的环境隔离不在源,而在参数、配置和代码层的配合。漏掉 --no-dev 或混淆 autoload-dev 作用,比镜像慢十倍还致命。

















