根本原因是php扩展在多个.ini文件中被重复启用extension=或zend_extension=指令,需先通过frankenphp php-cli -i确认实际加载路径,再搜索并注释conf.d/下冗余的扩展声明,最后重启验证。

FrankenPHP 1.4 启动时报“Module 'xxx' already loaded”这类错误,根本原因不是 FrankenPHP 本身的问题,而是 PHP 扩展在多个 .ini 文件中被重复启用了 extension= 或 zend_extension= 指令。FrankenPHP 使用的是标准 PHP SAPI,加载机制与 CLI 或 FPM 一致,因此必须按 PHP 配置规范清理冗余项。
第一步:确认实际生效的 php.ini 路径和扫描目录
运行以下命令,明确 FrankenPHP 加载配置的真实路径:
frankenphp php-cli -i | grep -E "(Configuration|Scan for additional)"
输出中重点关注两行:
-
Loaded Configuration File:主 php.ini 路径(如
/etc/php/8.2/cli/php.ini) -
Scan for additional .ini files in:额外加载目录(如
/etc/php/8.2/cli/conf.d/)
所有 conf.d/ 下的 .ini 文件都会被顺序解析,重复声明就在此处发生。
第二步:定位哪个扩展被重复加载
先看报错中的模块名(比如 opcache、pdo、curl),再用以下命令搜索所有启用位置:
grep -r "extension=.*opcache\|zend_extension=.*opcache" /etc/php/8.2/cli/conf.d/
常见冲突场景:
-
opcache.ini和php.ini都写了zend_extension=opcache.so -
pdo.ini启用了extension=pdo,而pdo_mysql.ini又写了同一行(错误!只需extension=pdo_mysql) - 某些一键脚本或 Docker 镜像在
conf.d/下生成了多个含相同 extension 的文件
第三步:安全清理冗余加载项
✅ 正确原则:
-
基础扩展(pdo、mysqli、curl、json 等)只在一个文件中启用,推荐统一放在
php.ini或一个专用00-base.ini - 依赖型扩展(pdo_mysql、pdo_pgsql、redis)不重复加载基础扩展,它们自动依赖已加载的 PDO 核心
- zend_extension(opcache、xdebug)必须全局唯一且不能混用普通 extension 指令,且不能出现在多个文件里
操作建议:
- 注释掉
conf.d/中非必需的extension=行,保留最上游的那个 - 删除空的或重复的
.ini文件(如20-pdo.ini和30-pdo.ini共存时留一个) - 改完后执行
php -v验证是否还有警告;无报错再启动 FrankenPHP
第四步:验证 FrankenPHP 是否真正加载成功
启动时加 --debug 参数观察 stderr 输出:
frankenphp serve --debug --document-root ./public
若不再出现 Module 'xxx' already loaded,且 php -m | grep xxx 显示该模块已加载,说明修复完成。注意:FrankenPHP 不会自动重读 ini 文件,每次修改后都需重启进程。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











