FrankenPHP 不兼容 mod_php 的隐式共享行为:register_globals 已彻底移除,全局变量不再自动注入;全局资源跨请求残留会导致经典模式下重复初始化、Worker 模式下连接错乱;Apache 特有 $_SERVER 键(如 REDIRECT_STATUS)缺失需手动补全或重构路由逻辑。

mod_php 的核心行为是:PHP 解释器常驻 Apache 进程,全局变量、静态属性、数据库连接等在请求间可复用,且 register_globals(已废弃)等旧机制曾被默认启用。FrankenPHP 不兼容这些行为——它默认按现代 PHP 运行时模型设计,每个请求在经典模式下仍是隔离的;Worker 模式虽常驻内存,但明确要求「无状态」,会主动清理全局污染。
所以,老项目若直接依赖 mod_php 的隐式共享或全局变量注入,迁移到 FrankenPHP 会出问题,不是配置能绕过去的。
register_globals 或 $_REQUEST 直接赋值到全局变量的代码会失效
这类代码在 mod_php 下能跑,在 FrankenPHP(任何模式)下必然失败:
// 请求 ?user_id=123,期望 $user_id 自动存在 echo $user_id; // FrankenPHP 中:Notice: Undefined variable
- FrankenPHP 使用标准 CGI/SAPI 模式启动 PHP,
register_globals早在 PHP 5.4 就被移除,FrankenPHP 内置的 PHP 版本(≥8.1)根本不会解析该指令。 - 即使你手动在
php.ini里写register_globals = On,FrankenPHP 启动时会忽略并报 Warning(可通过frankenphp php-cli-m查看加载的 ini 文件和警告)。
解决方式只有重构:
立即学习“PHP免费学习笔记(深入)”;
- 全局搜索
$[a-zA-Z_]变量名是否仅靠外部输入隐式创建 - 统一改用
$_GET、$_POST显式取值 - 若逻辑复杂,可封装一个兼容层(临时过渡):
if (!isset($user_id)) { $user_id = $_REQUEST['user_id'] ?? null; }
全局资源(如 $db、$cache)跨请求残留导致行为错乱
mod_php 下常见这种写法:
global $db;
if (!$db) {
$db = new PDO(...); // 只初始化一次
}
$db->query(...); // 复用连接在 FrankenPHP 经典模式下,每次请求都是全新进程,$db 永远为 null,看似“安全”,实则掩盖了连接未释放、事务未提交等问题;在 Worker 模式下,$db 会跨请求残留,但连接可能已断、事务未清理,直接复用大概率报错或数据错乱。
关键判断点:
- 如果你没显式调用
unset($db)或$db = null,就别指望它自动重置 - Worker 模式下,PHP 生命周期变长,
__destruct不再可靠,register_shutdown_function也未必触发
必须做两件事:
- 所有全局资源初始化逻辑移到请求入口(如
public/index.php开头)或服务容器中,确保每次请求都走完整初始化+销毁流程 - 禁用所有“复用连接”的幻想,改用连接池(如 Laravel 的
DB::connection()自带复用逻辑)或显式关闭:$db = null;
$_SERVER 中某些 mod_php-specific 键缺失(如 REDIRECT_STATUS)
Apache + mod_php 会在重写后注入 REDIRECT_STATUS、REDIRECT_URL 等键,部分老框架(如早期 CodeIgniter)靠它们判断路由是否被重写。
FrankenPHP 使用 Caddy 路由,不模拟这些 Apache 行为。你可能会看到:
Undefined index: REDIRECT_STATUS- 路由始终 fallback 到首页
检查你的入口文件是否依赖这些键:
- Laravel 不依赖,无需处理
- CodeIgniter 3.x 默认依赖,需在
index.php顶部补全:$_SERVER['REDIRECT_STATUS'] = '200'; $_SERVER['REDIRECT_URL'] = $_SERVER['REQUEST_URI'] ?? '/';
更稳妥的做法是:换掉判断逻辑,直接用 $_SERVER['REQUEST_URI'] 和 $_SERVER['REQUEST_METHOD'] 做路由分发,这才是现代 SAPI 的标准行为。
FrankenPHP 不是 Apache 的替代品,它是新范式的起点。老项目里那些靠 mod_php 隐式行为“凑合跑通”的代码,迁移时一定会暴露——这不是 FrankenPHP 的 bug,是你终于看清了原来那层薄薄的胶带早该撕掉了。



















