静态版 FrankenPHP 是单二进制,内置 Caddy、PHP 运行时及常用扩展(如 SQLite),无需系统 PHP 或额外配置,适合快速验证或受限环境部署,但无法更换 PHP 版本或添加自定义扩展。

静态版 FrankenPHP 是单二进制,不依赖系统 PHP
静态版(Standalone Binary)是 FrankenPHP 官方打包好的完整可执行文件,里面已经把 Caddy、PHP 运行时、应用代码(如 Koel)、SQLite 驱动全静态链接进去了。你下载解压后直接 ./frankenphp 就能跑,连系统里装没装 php 命令都不关心。
它适合这几种情况:
- 想零配置快速验证一个 PHP 应用(比如 Koel、Laravel demo)
- 部署环境受限,不能装系统级 PHP 或扩展(如某些容器或嵌入式设备)
- 不想管
php.ini、扩展开关、opcache 配置这些细节
但代价也很明确:你没法改 PHP 版本、没法加自定义扩展(比如 grpc 或 sqlsrv),所有行为都锁死在打包那一刻。
动态版 FrankenPHP 依赖系统 PHP,灵活但要自己配
动态版指的是通过包管理器(如 APT、Homebrew)安装的 frankenphp 命令,它本身不带 PHP 解释器,而是运行时调用系统已安装的 PHP —— 比如 Ubuntu 上它会去找 /usr/bin/php8.2,macOS 上可能走 php@8.2。
立即学习“PHP免费学习笔记(深入)”;
这意味着你能:
- 自由切换 PHP 版本(只要系统装了多个
php8.1/php8.3) - 用
pecl install装扩展,再在php.ini里启用 - 复用现有
opcache.preload、memory_limit等调优配置 - 配合
php-fpm共存调试(比如对比性能)
但也要自己处理依赖冲突、扩展 ABI 兼容性、以及 frankenphp 二进制和系统 PHP 的版本对齐问题 —— 比如用 PHP 8.3 编译的扩展,可能无法被 FrankenPHP 动态加载。
Worker 模式下,静态版和动态版的启动脚本行为不同
当你用 Laravel Octane 启动 Worker 模式时,两种版本的 frankenphp-worker.php 加载路径和权限逻辑其实是一致的,但底层行为有差异:
- 静态版:worker 脚本由内置 PHP 执行,
$_SERVER快照、opcache 行为、扩展能力全部来自打包时的快照 - 动态版:worker 脚本由系统 PHP 执行,所以
extension_loaded('redis')的结果取决于你系统里实际装了什么 - 两者都会忽略
php.ini中的disable_functions—— 因为 FrankenPHP 自己控制函数白名单,不是靠 ini 文件
最容易踩的坑是:你在动态版里确认 php -m | grep pdo_mysql 有输出,但 FrankenPHP 启动时报 Class 'PDO' not found。这不是扩展没装,而是 FrankenPHP 默认禁用了 pdo 扩展(出于安全沙箱考虑),得在 frankenphp.yaml 的 php.extensions 下显式加上 pdo 和 pdo_mysql。
监控指标暴露方式在两种版本里完全一致
无论静态还是动态,只要启用了 Caddy 的 metrics(即配置里有 admin: localhost:2019 并且开了 metrics),FrankenPHP 就会往 Prometheus 注册表里写指标,比如 frankenphp_busy_threads 和 frankenphp_queue_depth。
但注意一点:静态版的指标采集粒度更“干净”,因为它没有系统 PHP 的各种外部模块干扰;而动态版如果系统 PHP 装了一堆 Xdebug、Blackfire 插件,可能会影响指标上报延迟或触发额外 GC,导致 frankenphp_total_threads 波动异常。
真正容易被忽略的是:指标只在 Caddy admin 接口启用时才存在,不是 FrankenPHP 自己开个端口 —— 所以哪怕你用静态版,也得确保 caddy run 启动时带了 --admin localhost:2019,否则 curl http://localhost:2019/metrics 会 404。



















