php_server 是 FrankenPHP 的内置 HTTP 服务器模式,将 Caddy 路由、TLS、静态文件服务与 PHP 执行集成于单进程,支持自动 HTTPS、HTTP/3 和 index.php 回退,但需 Caddyfile 配置且不兼容 Laravel 默认 public 目录结构。

php_server 是 FrankenPHP 的内置 Web 服务器模式
php_server 启动的是一个完整 HTTP 服务,它把 Caddy 的路由、TLS、静态文件、PHP 执行全包了。你执行 frankenphp php_server,就等于同时启动了 Nginx + PHP-FPM + certbot + HTTP/3 支持——全部在一个进程里跑。它默认监听 :8080,自动处理 .php 文件,也支持 index.php fallback 和重写规则(靠 Caddyfile 控制)。
常见错误现象:php_server 启动后访问空白页或 404,大概率是没放 Caddyfile,或者当前目录下没有可被路由的 index.php;它不会自动 fallback 到 public/index.php,这点和 Laravel 默认结构不兼容,得手动配 handle / { rewrite * /index.php } 或类似规则。
- 它不读系统级
php.ini,只认 FrankenPHP 自带的运行时配置(可通过FRANKENPHP_PHP_CONFIG环境变量覆盖) - 不支持
$_SERVER['SCRIPT_FILENAME']自动推导,框架常依赖这个字段定位入口,容易报“file not found” - 静态资源(如
/css/app.css)默认由 Caddy 直接返回,不走 PHP,这点比传统 FPM 更快但更“不透明”——调试时别误以为是 PHP 路由没生效
php 是 FrankenPHP 的 CLI 模式,等价于系统 php 命令
php 子命令本质是调用嵌入的 PHP 解释器执行脚本,不启动任何网络服务。它和你在终端敲 php script.php 行为一致:加载扩展、解析语法、执行、退出。区别在于它用的是 FrankenPHP 自带的 PHP 运行时,版本和扩展与 php_server 完全一致,且无需系统已安装 PHP。
使用场景很明确:跑迁移、队列、定时任务、单元测试、或者调试单个脚本。比如 Laravel 的 php artisan migrate 在 FrankenPHP 环境下就得写成 frankenphp php artisan migrate。
立即学习“PHP免费学习笔记(深入)”;
- 它不读
Caddyfile,也不管 HTTP 请求,纯 CLI 上下文 -
$_SERVER数组是空的(或只有极简模拟),别指望它有REQUEST_URI或HTTP_HOST - 如果你在脚本里写了
echo "hello"; exit;,输出会直接打到终端,不会被当成 HTTP 响应体
为什么不能用 php_server 直接跑 artisan 命令
因为 php_server 是 HTTP server,它只响应 HTTP 请求,不接受 CLI 参数。你执行 frankenphp php_server artisan migrate 会报错:未知子命令或参数被忽略——php_server 根本不解析后面的参数。
反过来,frankenphp php 也无法处理 HTTP 请求,它压根不监听端口。试图用它启动一个 Web 应用(比如直接跑 frankenphp php public/index.php)会导致请求头缺失、路由失效、Session 不可用等问题,框架通常会直接崩溃或返回 500。
- 两者运行时环境隔离:
php_server初始化了 HTTP 上下文(包括全局 request/response 对象、Caddy 的 context)、而php是 clean slate CLI 环境 - 扩展加载行为一致,但 ini 设置可能不同:CLI 模式默认关闭
opcache.enable_cli,而php_server默认开启 opcache(影响类加载性能) - worker 模式只对
php_server生效;php命令永远是“一次一启”,无法常驻
实际部署中容易混淆的点
最常踩的坑是误把开发时的 php_server 当成生产 Web 服务直接上线,却忘了它默认不启用 worker 模式、也没开 HTTPS、日志级别太低。另一个高频问题是:在 CI/CD 脚本里混用两个命令,比如用 php_server 启动后立刻发 HTTP 请求去触发迁移——这根本行不通,因为迁移必须走 CLI。
-
php_server的配置全靠Caddyfile,没这个文件它连路由规则都没有;php完全无视该文件 - 路径处理差异大:
php_server的工作目录是 Caddyfile 所在目录;php的工作目录是你执行命令时所在的目录 - 错误信息输出位置不同:
php_server错误进 Caddy 日志(默认 stdout);php错误直接打终端,且不带时间戳
worker 模式只存在于 php_server 中,且必须显式开启;php 命令永远是瞬时执行,这点决定了所有需要常驻内存的场景(比如长连接、事件监听)只能走 php_server + worker。



















