最主要原因是在frankenphp中未启用laravel所需的扩展(如pdo_mysql、redis、intl等),因其内置php仅默认加载基础扩展,而php-cli -m显示的列表不反映实际启用状态,需手动在php.ini中开启并验证。

排最前面的原因是:没确认 php.ini 中启用的扩展和 Laravel 实际依赖的扩展不匹配。
为什么这个错误总在迁移第一分钟就暴露
FrankenPHP 内置 PHP 运行时,但默认只开基础扩展(json、mbstring、xml 等),而 Laravel 项目往往依赖 pdo_mysql、redis、intl、gd、bcmath 等——这些不会自动加载,必须显式启用。
现象很典型:frankenphp serve 启动成功,但访问首页直接报 Class 'PDO' not found 或 Call to undefined function Illuminate\Support\str_slug()(实为 mbstring 缺失);或者 composer install 阶段就失败,提示 ext-pdo_mysql 不可用。
- FrankenPHP 的
php-cli -m输出不等于你项目运行时实际加载的模块——它只反映二进制内置的扩展列表,不反映是否被启用 -
php.ini路径容易被忽略:FrankenPHP 默认不读系统级/etc/php/*/cli/php.ini,而是优先用内置路径或 Caddyfile 指定的php.ini - Docker 场景下,
install-php-extensions命令必须在COPY ./app之前执行,否则构建缓存会跳过扩展安装
怎么快速验证并修复
在 FrankenPHP 进程里直接跑一句诊断命令:
frankenphp php-cli -r "print_r(get_loaded_extensions());"
对比你的 composer.json 里 require 下的 ext-* 条目,缺哪个补哪个。常见操作如下:
- 本地二进制部署:编辑
php.ini,取消注释对应行,例如extension=pdo_mysql - Docker 部署:确保
RUN install-php-extensions在COPY之前,且参数拼写完全匹配(pdo_mysql≠pdo_mysql.so) - 使用
frankenphp php-cli -i | grep 'Loaded Configuration File'确认当前生效的php.ini路径,别改错文件
经典模式下最容易被忽略的兼容点
“零改动”只针对代码逻辑,不包括环境假设。Laravel 默认认为 $_SERVER['REQUEST_URI'] 和 $_SERVER['SCRIPT_NAME'] 是由 Nginx/FPM 构造好的,而 FrankenPHP 经典模式虽然模拟了 FastCGI 行为,但某些边缘路径解析(比如带 query string 的重写规则)仍可能让 url()->full() 返回异常值。
这不是 bug,是行为差异——它只在你项目里重度依赖 $_SERVER 原始值做路由判断或签名计算时才会浮现,而且复现条件隐蔽,调试成本远高于扩展缺失。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











