根本原因是frankenphp以vendor/bin/frankenphp-worker.php为入口在项目根目录运行,导致相对路径基准变为项目根而非当前文件目录;必须用__dir__拼接绝对路径或显式定义base_path统一管理。

FrankenPHP 嵌入应用后相对路径失效,根本原因不是 PHP 解析错了,而是 __DIR__ 和 require_once 的行为没变,但执行上下文变了——你写的 require '../config.php' 仍按当前工作目录(CWD)解析,而 FrankenPHP 启动时的 CWD 往往是项目根目录(composer.json 所在处),不是 public/index.php 或某个中间件脚本所在位置。
为什么 ../config.php 在 FrankenPHP 里突然找不到
传统 Apache/Nginx + PHP-FPM 环境下,index.php 是直接被 Web 服务器作为入口调用的,CWD 通常就是它所在目录;FrankenPHP 却以 vendor/bin/frankenphp-worker.php 为实际入口,该脚本在项目根目录运行,再加载 public/index.php。结果所有相对路径都从项目根开始算,../config.php 就变成了“项目根目录上一级”,自然失败。
-
public/index.php里写require '../config.php'→ 实际查的是/path/to/project/../config.php,而非/path/to/project/public/../config.php - 即使你在
app/Http/Controllers/PostController.php里写include '../../config.php',它仍按项目根目录算层级,不是按控制器文件物理位置 -
getcwd()返回的是项目根目录,不是文件所在目录,不能用来拼路径
必须用 __DIR__ 替代所有相对路径
__DIR__ 是编译期确定的、指向当前文件**物理目录**的绝对路径,不受执行位置影响,是 FrankenPHP 下唯一可靠的路径锚点。
- 把
require '../config.php'改成require __DIR__ . '/../config.php';(假设config.php在项目根) - 在
public/index.php中加载框架启动逻辑时,不要写require 'bootstrap/app.php',而要写require __DIR__ . '/../bootstrap/app.php'; - 若项目结构是
app/Models/User.php需要加载app/Config/database.php,就用require __DIR__ . '/../Config/database.php';,而不是靠../../猜层级
框架级路径管理要显式声明根目录
Laravel、ThinkPHP 等框架默认依赖 $_SERVER['DOCUMENT_ROOT'] 或自动推导根路径,但在 FrankenPHP 的 embed SAPI 下,这些变量可能为空或不准。必须手动固化根路径。
- 在
public/index.php开头立即定义:define('BASE_PATH', dirname(__DIR__));(__DIR__是public/目录,dirname(__DIR__)就是项目根) - 后续所有加载统一用:
require BASE_PATH . '/config/app.php';、require BASE_PATH . '/app/Helpers/Utils.php'; - 避免使用
$_SERVER['DOCUMENT_ROOT']构建路径——FrankenPHP 不保证它被正确设置,且 Docker 容器中常为空
别信 set_include_path(),它不解决根本问题
有人试过用 set_include_path(get_include_path() . PATH_SEPARATOR . __DIR__ . '/../'); 再写 require 'config.php',看似能用,但隐患很大:
- 一旦某处调用
require时没重置 include_path,就会沿用旧值,路径混乱 FrankenPHP 的 worker 脚本会多次复用进程,include_path 可能被前一次请求污染
- 静态分析工具(如 PHPStan)和 IDE 很难追踪这种动态路径,类型推导失效
- 更关键的是:它掩盖了路径设计缺陷,不如直接用
__DIR__显式表达意图
最易被忽略的一点:FrankenPHP 的 vendor/bin/frankenphp-worker.php 是生成的脚本,它内部硬编码了部分加载逻辑。如果你改了项目结构(比如把 config/ 移到 src/Config/),光改 index.php 不够,还得重新运行 php artisan octane:install --server=frankenphp 让 worker 脚本同步更新路径引用——否则旧脚本仍按老结构找文件,报错却提示不到具体哪一行。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











