只有写入require或require-dev字段的ext-*条目才会触发Composer安装时的扩展启用检查;conflict中声明无效,因conflict仅参与版本求解而不校验运行时环境。

composer.json 里怎么声明 ext-* 才生效
只有写进 require 或 require-dev 的 ext-* 条目,Composer 安装时才会真正检查扩展是否启用。写在 conflict 字段里没用——conflict 只参与依赖版本求解,不查运行时环境。
常见错误写法:"conflict": {"ext-curl": "*"},这不会阻止安装,也不会报错缺失 curl;正确写法是:
{
"require": {
"php": "^8.1",
"ext-curl": "*",
"ext-pdo": "^8.0",
"ext-mbstring": "^1.3"
}
}
说明:
-
ext-curl后面留空或写*,表示“只要启用即可”,不校验版本 - 写
^1.3这类约束时,Composer 会调用phpversion('curl')获取实际版本比对(部分扩展不支持返回版本号,此时约束会被忽略) -
ext-json在 PHP 8.0+ 中默认启用且无版本号,所以ext-json: "^1.5"在 8.0+ 环境下始终通过,但 7.x 下可能失败
为什么 composer install 没报错,但运行时报 Class not found
这不是 Composer 检测失效,而是自动加载器生成逻辑和 PHP 版本强相关。vendor/autoload.php 本身不绑定 PHP 版本,但它依赖的 autoload_static.php 或反射行为,在不同 PHP 版本下可能生成不同映射。
典型现象:
- 用 PHP 8.2 跑过
composer install,生成了带 PHP 8.2 特性的 autoload_static - 切到 PHP 8.0 运行,
class_exists()或 PSR-4 映射失败,报Class not found - 但
php -m | grep curl显示扩展已启用,composer install也安静通过
根本原因:Composer 只在校验阶段检查扩展是否存在,不验证类文件能否被当前 PHP 版本加载。解决办法只有一条:
每次切换 PHP 版本后,必须删掉 vendor/ 和 composer.lock,再重新 composer install —— 复用旧 vendor 是最常被忽略的坑。
如何跳过某个 ext-* 检查(仅限 CI 或临时调试)
生产环境不该跳过,但 CI 流水线里有时需要绕过非关键扩展(比如 ext-xdebug 在测试镜像里未装)。有两种方式,效果不同:
- 设环境变量:
COMPOSER_DISABLE_EXTENSIONS=1 composer install,这会让 Composer 完全跳过所有ext-*校验 - 在
config.platform里“伪造”扩展存在:"platform": {"ext-gd": "0"},这相当于告诉 Composer “gd 已安装,版本是 0”,能骗过require但无法绕过conflict
注意:config.platform 是静态模拟,它不改变真实环境,也不影响运行时行为;而 COMPOSER_DISABLE_EXTENSIONS 是全局关闭,CI 里用完要记得恢复。
ext-* 冲突和 php 版本冲突混在一起怎么定位
当 composer install 报错类似 - Root package requires ext-curl (*), but it is not present,但 php -m 明明有,大概率是 PHP SAPI 不一致。
必须分两步确认:
- CLI 环境:执行
php -v和php -m | grep curl - Web 环境:建一个
info.php输出phpinfo(),看Server API(Apache/FPM/CLI)和Loaded Configuration File路径
常见陷阱:cPanel、Plesk 默认为域名单独指定 PHP 版本,CLI 用的是系统默认 PHP,Web 用的是面板选的 PHP,二者 php.ini 完全不同,extension=curl.so 可能只在其中一个里启用。这时候改 composer.json 没用,得去面板里开扩展。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











