frankenphp 支持 symfony 5,需 php ≥7.4(推荐 8.0+)、启用 mbstring/intl/json/xml/ctype/session/zlib/opcache 等扩展,worker 模式下须规避全局状态残留、调整 session 和日志处理。

能,但得先确认 PHP 版本和扩展依赖是否满足最低要求。
FrankenPHP 对 Symfony 本身没有版本锁死,它只关心你项目运行时的 PHP 版本、扩展是否就位,以及是否用了某些与常驻内存冲突的惯用写法(比如在全局作用域里 new PDO 或直接写 register_shutdown_function)。Symfony 5 项目只要跑在 PHP 7.4+(推荐 8.0+),基本都能平滑迁移——我们线上一个 Symfony 5.4 + PHP 8.1 的后台系统已经稳定跑在 FrankenPHP worker 模式下三个月了。
检查 PHP 版本和关键扩展
- FrankenPHP 官方要求 PHP ≥ 7.4,但 Symfony 5.4 实际需要 PHP ≥ 7.2.5;不过
frankenphp二进制本身是用 Go 编译的,它内嵌的 PHP 运行时版本必须匹配你的代码逻辑 - 必须启用的扩展:
mbstring、intl、json、xml、ctype、session、zlib -
opcache强烈建议开启且配置为永久启用(opcache.enable_cli=1在 worker 模式下生效) - 如果用了
apcu做缓存,注意 FrankenPHP 的 CLI 模式下 APCu 是可用的,但需确认apc.enable_cli=1
Symfony 5 项目启动方式要微调
FrankenPHP 不走 index.php 入口转发,而是直接加载 PHP 脚本并复用进程。这意味着:
- 不能依赖
$_SERVER['SCRIPT_NAME']或$_SERVER['REQUEST_URI']的传统 CGI 行为,FrankenPHP 会注入标准化的 SAPI 环境变量 -
public/index.php需保留,但实际入口应指向frankenphp自动识别的index.php(它会自动找 public/ 下的) - 若你项目用了自定义的
bootstrap.php或提前 require 了某些全局文件,得确保它们不依赖每次请求都重执行的副作用(比如重复注册 autoloader)
worker 模式下最容易踩的坑
-
Kernel::boot()只执行一次,所有请求共享同一个容器实例 → 不能在服务构造函数或__construct()里写“每次请求都要 fresh”的逻辑(如 new DateTime()、new PDO()) -
$_SESSION默认不可用(因为无原生 session handler 绑定),要用Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHandler或适配frankenphp提供的frankenphp_session_start() - 日志写入可能卡住:如果用了
StreamHandler写文件,多个请求共用一个 file handle 会导致竞争;改用RotatingFileHandler并设filePermission=0644,或切到syslog/monolog的SocketHandler
快速验证能不能跑通
- 先不用 worker 模式,用 classic 模式启动:
frankenphp php-server --document-root=public/ - 访问
@#@#@#@#@#@#@#@#@#@0,看是否正常渲染首页(Caddy 默认启 HTTPS + HTTP/3) - 再加
--worker启动:frankenphp php-server --document-root=public/ --worker - 观察首次访问是否慢(框架 boot 阶段)、后续请求是否明显变快(
microtime(true)打点对比Kernel::boot()耗时)
复杂点在于「状态残留」——比如 Doctrine EntityManager、Redis 连接、Monolog 的 handlers,在 worker 生命周期里不会自动重置。这不是 FrankenPHP 的 bug,而是常驻模型的必然约束。你得主动在请求开始/结束时做 reset 或 clone,或者改用 request-scoped service。这点比部署本身更花时间。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











