FrankenPHP完全静态二进制因禁用dlopen()而无法加载任何外部.so扩展,如redis.so、pdo_mysql.so、gd.so等;可通过file(显示statically linked)和ldd(报错not a dynamic executable)确认是否为静态版。

FrankenPHP 静态二进制为何拒绝加载 .so 扩展
因为“完全静态”指的是整个二进制(含 PHP 运行时)在编译时已将所有依赖代码打包进单一文件,dlopen() 系统调用被禁用或失效,导致运行时无法动态加载任何外部 .so 文件。
哪些扩展会直接失败
所有依赖 dlopen() 的常规 PHP 扩展都会静默跳过或报错,典型包括:
-
redis.so、pdo_mysql.so、gd.so—— 即使 php.ini 里写了extension=redis,启动日志也不会报错,但php -m查不到 -
opcache.so—— 官方静态构建默认已内置,但若你手动删了zend_extension=opcache.so行,就真没了,且无提示 -
fileinfo.so、mbstring.so—— 这些常被误认为“基础扩展”,实则多数发行版是动态编译的
怎么确认你用的是完全静态二进制
别只看名字带 “static” —— 关键看行为和输出:
- 运行
file frankenphp,若输出含statically linked,基本确定是完全静态 - 运行
ldd frankenphp,若报错not a dynamic executable,就是静态的 - 执行
frankenphp php-cli -m | grep -E '^(redis|pdo_|gd)$',空输出 ≠ 没装,极可能因静态限制未加载 - 检查
php --ini输出的配置路径:完全静态版通常硬编码/usr/local/lib/php.ini或类似路径,且不响应-c参数
替代方案不是“换回动态版”,而是换思路
静态二进制的设计目标是零依赖部署,所以它把部分关键扩展直接编译进 PHP 引擎本身:
立即学习“PHP免费学习笔记(深入)”;
- 用
php -r "print_r(gd_info());"测试 GD —— 若返回数组而非 fatal error,说明 GD 已内置(无需gd.so) - 查
php -i | grep "PDO drivers"—— 若显示mysql, sqlite,说明 PDO 驱动已 baked-in,不用额外pdo_mysql.so - 运行
php -r "echo opcache_get_status()['opcache_enabled'] ?? 'off';"—— 返回1表示 OPcache 不靠.so,而是编译时启用的 Zend 扩展 - 若项目真缺某个未内置的扩展(如
swoole),唯一办法是放弃静态二进制,改用dunglas/frankenphp:alpine或自建 musl/glibc 动态镜像
真正容易被忽略的是:静态 ≠ 功能全。它只是把“能安全打包进单文件”的扩展编译进去,其余一律剔除。别在 php.ini 里徒劳地写 extension=xxx,那行根本不会被执行。



















