答案:需在scripts中用extension_loaded('mysqlnd')配合exit(1)显式中断,扩展名必须小写无后缀,且确保CLI环境已启用——因Composer脚本运行于PHP CLI SAPI,只认php -m输出的模块名。

Composer脚本里怎么判断ext-mysqlnd是否可用?
直接在composer.json的scripts里用extension_loaded()就行,但要注意执行环境——Composer默认用CLI SAPI运行脚本,和Web环境无关,所以只看php -m输出的扩展列表。
常见错误是写成if (!extension_loaded('pdo_mysql')) { die(); }却没加exit(1),导致Composer误判脚本成功;或者把扩展名写成pdo_mysql.so(带后缀)或PDO_MYSQL(全大写),实际必须用小写、无后缀的标准名。
-
extension_loaded('openssl')→ ✅ 正确 -
extension_loaded('OpenSSL')→ ❌ 失败 -
extension_loaded('openssl.so')→ ❌ 失败 - 脚本末尾没
exit(0)或exit(1)→ Composer认为“成功”,即使逻辑报错
怎么让composer install失败时自动提示缺失扩展?
把检查逻辑塞进post-install-cmd或自定义命令里,用exit(1)触发中断。别依赖require里的ext-xxx——那只是声明依赖,不校验运行时是否真加载了。
例如:在composer.json中定义:
立即学习“PHP免费学习笔记(深入)”;
"scripts": {
"check-extensions": "php -r "if (!extension_loaded('mbstring')) { echo 'ext-mbstring missing\n'; exit(1); }"",
"post-install-cmd": ["@check-extensions"]
}
注意:php -r里换行要用\n,单引号内变量不展开;如果扩展名含下划线(如apcu),别写成apc_u。
为什么ext-gd明明装了,extension_loaded('gd')还返回false?
CLI和Web用的PHP配置文件(php.ini)可能不同。运行php --ini确认CLI用的是哪个ini,再查里面是否启用了extension=gd(不是extension=gd.so,Windows下是php_gd2.dll)。常见坑:
- Ubuntu上
php-gd包装了,但CLI ini里没开extension=gd - Docker里用
alpine镜像,apk add php7-gd后需手动改ini或用docker-php-ext-enable gd - Mac M1用Homebrew装PHP,
gd可能被编译进PHP二进制而非动态扩展,extension_loaded('gd')仍返回true,但php -m | grep gd看不到
能不能在composer.json里声明“必须启用某扩展”并自动检查?
不能。Composer的require字段只支持ext-xxx作为包依赖约束,它只在composer install前检查php -m输出,且不区分CLI/Web上下文。一旦安装完成,后续脚本运行时扩展可能被禁用(比如改了ini但没重启PHP-FPM),这时必须靠脚本主动检查。
所以真实项目里得两手抓:
-
"require": {"ext-mbstring": "*"}→ 安装前拦住没装扩展的人 -
"post-autoload-dump": "php -r "if (!extension_loaded('mbstring')) exit(1);""→ 运行时再拦一次,防ini被改
扩展加载状态不是静态的,每次CLI调用都得重新检查,尤其在CI/CD里,基础镜像可能删掉某些扩展。



















