
FrankenPHP 开发者贡献指南源码编译、测试套件与调试工作流【免费下载链接】frankenphp The modern PHP app server项目地址: https://gitcode.com/GitHub_Trending/fr/frankenphp本指南以 FrankenPHP 仓库的 docs/fr/CONTRIBUTING.md法语版贡献文档为核心面向想要参与 FrankenPHP 开发、或需要从源码构建、调试该现代 PHP 应用服务器的开发者。文章完整覆盖从搭建 Docker 开发环境、编译 PHP 与 Caddy 模块、运行测试套件、构建本地 Docker 镜像到使用 GDB 排查段错误segfault的完整工作流并结合仓库源码解释每一步背后的实现细节。读完本文你将掌握一套可复现的 FrankenPHP 本地开发与调试流程。一、FrankenPHP 开发环境总览FrankenPHP 是一个基于 Caddy Web 服务器、通过 cgo 将 PHP 作为嵌入式运行时集成进来的 PHP 应用服务器。因此它的开发链路天然分为两部分PHP 侧需要编译出带 ZTSZend Thread Safety的嵌入式libphp.soGo 侧需要把 PHP、Caddy、Mercure、Vulcain 等模块通过go build或xcaddy打包成单个可执行文件。仓库中 caddy/frankenphp/main.go 清楚地展示了这一点主程序导入了 Caddy 标准模块、github.com/dunglas/frankenphp/caddy以及 Mercure、Vulcain 模块后直接调用caddycmd.Main()启动。go.shgo.sh则是仓库内统一封装 Go 构建命令的脚本它会自动注入-tagsnobadger,nomysql,nopgx以及CGO_CFLAGS/CGO_LDFLAGS通过php-config动态获取 PHP 头文件与链接参数保证任何使用该脚本的构建都能正确链接 PHP。理解这条链路是读懂下文所有构建与调试命令的前提。二、使用 Docker 编译 PHPLinux2.1 构建并进入开发镜像FrankenPHP 提供了专用的开发镜像定义 dev.Dockerfile里面预装了 Go、GDB、Valgrind、Neovim、Clang、CMake 等调试与开发工具。构建并运行docker build -t frankenphp-dev -f dev.Dockerfile . docker run --cap-addSYS_PTRACE --security-opt seccompunconfined -p 8080:8080 -p 443:443 -p 443:443/udp -v $PWD:/go/src/app -it frankenphp-dev逐项解释这些参数参数作用--cap-addSYS_PTRACE允许容器内使用ptrace否则 GDB 无法附加到进程--security-opt seccompunconfined解除 seccomp 限制避免干扰调试器-p 8080:8080/-p 443:443/-p 443:443/udp暴露 HTTP、HTTPS 与 HTTP/3QUIC端口-v $PWD:/go/src/app将当前仓库挂载进容器实现代码热同步-it frankenphp-dev交互式进入容器默认 shell 为 zsh见 dev.Dockerfile 的CMD2.2 镜像内的 PHP 配置位置dev 镜像内部编译的是 PHP 8.5 源码见 dev.Dockerfile 中git clone --branchPHP-8.5并在./configure阶段显式指定了以下路径php.ini/etc/frankenphp/php.ini镜像默认把php.ini-development复制为该文件并追加启用了zend_extensionopcache.so与opcache.enable1额外的配置文件/etc/frankenphp/php.d/*.ini对应--with-config-file-scan-dirPHP 扩展/usr/lib/frankenphp/modules/对应EXTENSION_DIR/usr/lib/frankenphp/modules。编译命令中还有两个值得注意的开关--enable-zts线程安全FrankenPHP 必须、--enable-debug开启 PHP 调试符号它们与下文 GDB 调试环节直接相关。2.3 低版本 Docker 的构建问题如果 Docker 版本低于 23.0构建可能因为 .dockerignore 中的 pattern 问题而失败这与 Docker 旧版本对排除规则!语义的实现差异有关。修复方法是把caddy和internal目录显式加回.dockerignore!testdata/*.php !testdata/*.txt !caddy !internal三、不使用 DockerLinux / macOS 本地编译如果不想用容器可以按照仓库根目录下的 docs/compile.md 从源码编译并额外传入--debug配置开关来获得带调试信息的 PHP。关键步骤包括安装或编译带 ZTS 的 PHPLinux/macOS 均可使用 Homebrew 的shivammathur/php/php-zts或自行用--enable-embed --enable-zts --disable-zend-signals --enable-zend-max-execution-timers编译按需安装 Brotli压缩支持与 watcher文件变更监听用于 worker 热重载用go build或xcaddy链接 PHP 编译出最终二进制。需要说明的是FrankenPHP 要求 PHP 8.2 及以上版本且必须以 ZTS 模式编译可选依赖则可通过 Go build tagsnobrotli、nowatcher、nomercure关闭。四、运行测试套件4.1 库级测试在仓库根目录执行go test -race -v ./...-race启用 Go 竞态检测器race detector-v输出每个测试的详细信息。该命令会测试仓库根目录下的核心 Go 包如 frankenphp.go、worker.go、hotreload.go 等。仓库中还包含大量对应测试文件例如 frankenphp_test.go、worker_test.go、worker_internal_test.go、scaling_test.go 等。CI 中见 .github/workflows/tests.yaml使用了gotestsum汇总输出并同样以-race方式运行。需要说明的是运行该测试套件前通常需要先通过.github/actions/setup-php见 .github/actions/setup-php/action.yaml配置好 PHPphpts: ts、debug: true的 ZTS 调试模式环境并设置好CGO_CFLAGS/CGO_LDFLAGS。4.2 测试数据与服务器测试目录 testdata/ 下存放了大量 PHP 测试脚本如phpinfo.php、worker.php、early-hints.php等并有一个 testdata/Caddyfile 专门用于测试场景它启用了debug、注册了frankenphp模块、配置了.php路径转发、encode zstd br gzip压缩与 404 兜底。五、构建并运行 Caddy 模块版 FrankenPHP5.1 构建仓库的caddy/frankenphp目录是一个独立的 Go module包含带 FrankenPHP 模块的 Caddy 主程序。构建命令cd caddy/frankenphp/ go build -tags nobadger,nomysql,nopgx cd ../../nobadger、nomysql、nopgx三个 build tags 会排除 Caddy 的可选存储模块Badger、MySQL、Pgx从而显著缩小二进制体积并避免引入不必要依赖——这一点与 go.sh 中默认注入的-tagsnobadger,nomysql,nopgx完全一致。5.2 运行并验证cd testdata/ ../caddy/frankenphp/frankenphp run该服务器监听127.0.0.1:80配置见 testdata/Caddyfile 中的http://站点块[!NOTE] 如果在 Docker 中使用需要把容器的 80 端口映射出来或直接在容器内部执行。用 curl 验证 PHP 是否正常处理请求curl -vk http://127.0.0.1/phpinfo.php-k忽略证书校验-v输出详细请求/响应头便于确认 PHP 已通过 FrankenPHP 模块被正确执行。六、最小测试服务器internal/testserverinternal/testserver/main.go 提供了一个不依赖 Caddy 的最小 Go HTTP 服务器用于快速验证 FrankenPHP 的嵌入 API。构建与运行cd internal/testserver/ go build cd ../../cd testdata/ ../internal/testserver/testserver从源码看internal/testserver/main.go该程序的核心逻辑非常精简调用frankenphp.Init(frankenphp.WithContext(ctx), frankenphp.WithLogger(logger))初始化 PHP 运行时在根路径 handler 中通过frankenphp.NewRequestWithContext(r)包装请求再交给frankenphp.ServeHTTP(w, req)处理监听PORT环境变量指定的端口默认8080。验证curl -v http://127.0.0.1:8080/phpinfo.php这个最小服务器非常适合在做库级改动时快速回归验证也是理解 FrankenPHP 嵌入 APIInit/Shutdown/NewRequestWithContext/ServeHTTP的最佳入口。七、使用 Docker Buildx Bake 构建本地镜像仓库根目录的 docker-bake.hcl 定义了完整的镜像构建矩阵。先查看构建计划docker buildx bake -f docker-bake.hcl --print--print只输出 JSON 形式的构建计划而不实际构建。从该 HCL 可以看到镜像矩阵覆盖多个 PHP 版本8.2,8.3,8.4,8.5默认8.5多个基础系统trixie、bookworm、alpineAlpine 走 alpine.Dockerfile其余走 Dockerfilebuilder与runner两种 target支持linux/amd64、linux/386、linux/arm/v7、linux/arm64Alpine 额外支持arm/v6另外还有独立的static-builder-musl与static-builder-gnu静态构建 target对应 static-builder-musl.Dockerfile 与 static-builder-gnu.Dockerfile。实际构建本机 amd64 镜像docker buildx bake -f docker-bake.hcl --pull --load --set *.platformlinux/amd64--pull拉取最新基础镜像--load把构建结果载入本地 Docker--set *.platformlinux/amd64覆盖矩阵中所有 target 的平台。构建 arm64 同理docker buildx bake -f docker-bake.hcl --pull --load --set *.platformlinux/arm64从零完整构建 amd64 与 arm64 镜像并推送到 Docker Hubdocker buildx bake -f docker-bake.hcl --pull --no-cache --push--no-cache禁用构建缓存以保证可复现--push直接推送。注意docker-bake.hcl中定义了sha-hash、semver 版本号以及latest等多种 tag 规则并会写入org.opencontainers.image.*标签。八、用 GDB 调试静态构建的段错误FrankenPHP 混用 Go 与 CPHP段错误通常发生在 C 侧需要 GDB 定位。8.1 获取带调试符号的静态二进制从发布渠道下载调试版二进制或自行构建带符号的静态版本docker buildx bake \ --load \ --set static-builder.args.DEBUG_SYMBOLS1 \ --set static-builder.platformlinux/amd64 \ static-builder docker cp $(docker create --name static-builder-musl dunglas/frankenphp:static-builder-musl):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphpDEBUG_SYMBOLS1让静态构建保留调试符号第二条命令从构建容器中把对应架构的二进制拷贝出来。8.2 GDB 附加流程gdb -p pidof frankenphp若进程暂停在初始化阶段先在 GDB 里输入continue让程序继续运行然后复现崩溃崩溃后输入btbacktrace打印调用栈把输出粘贴到 issue 中。这一流程依赖开发镜像里预先配置的 GDB 设置dev.Dockerfile中写入了echo set auto-load safe-path / /root/.gdbinit和echo * soft core unlimited /etc/security/limits.conf前者允许加载系统库的自动调试脚本后者允许生成完整 core dump。九、在 GitHub Actions 中复现段错误当段错误只在 CI 中出现时可按以下步骤在 Actions 环境中交互式排查仓库对应 CI 定义在 .github/workflows/tests.yaml打开 CI 工作流文件在shivammathur/setup-php步骤对应 .github/actions/setup-php/action.yaml其中已设置phpts: ts启用 PHP 库调试符号- uses: shivammathur/setup-phpv2 # ... env: phpts: ts debug: true启用tmateSSH 远程调试终端以进入 CI 容器- name: Set CGO flags run: echo CGO_CFLAGS$(php-config --includes) $GITHUB_ENV - run: | sudo apt install gdb mkdir -p /home/runner/.config/gdb/ printf set auto-load safe-path /\nhandle SIG34 nostop noprint pass /home/runner/.config/gdb/gdbinit - uses: mxschmitt/action-tmatev3SIG34即 PHP 的 Zend 信号处理器使用的信号需要nostop noprint pass避免 GDB 被其频繁打断。通过 tmate 输出连接到容器打开 frankenphp.go启用cgosymbolizer使 GDB 能解析 Go 侧符号- //_ github.com/ianlancetaylor/cgosymbolizer _ github.com/ianlancetaylor/cgosymbolizer拉取该模块依赖go get在容器内用 GDB 运行测试go test -c -ldflags-w gdb --args frankenphp.test -test.run ^MyTest$go test -c编译出测试二进制-ldflags-w去掉 DWARF 调试表以加快链接之后可在 GDB 中run复现、bt取栈。修复 bug 后撤销上述所有临时改动再提交 PR。十、开发参考资料原文档还给出了若干有价值的开发参考均在文档中列出此处仅作指引不展开外部内容PHP 嵌入式集成范例uWSGI 的 PHP 插件、NGINX Unit 的nxt_php_sapi.c、Go 生态的 go-php 与 GoEmPHP、C 集成示例PHP 内核资料Sara Golemon 的《Extending and Embedding PHP》以及关于TSRMLS_CC的经典博客文章macOS 集成PHP 在 Mac 上的嵌入示例SDL 绑定Go 侧sdl.Main调用方式涉及运行时线程模型的参考实现Docker 资料Bake 文件定义与docker buildx build文档。十一、实用调试命令速查apk add strace util-linux gdb strace -e trace!futex,epoll_ctl,epoll_pwait,tgkill,rt_sigreturn -p 1strace附加到 PID 1 跟踪系统调用-e trace!...过滤掉futex、epoll_*、tgkill、rt_sigreturn等高噪声调用让输出聚焦在真正的文件与网络 I/O 上。这是排查进程无响应/卡死类问题时的常用手段。十二、翻译文档参与多语言贡献FrankenPHP 的文档采用英文为唯一源、多语言同步翻译的模式仓库docs/下已有cn/、es/、fr/、it/、ja/、pt-br/、ru/、tr/等多个语言目录。参与流程在仓库docs/下新建以该语言 ISO 2 字符代码命名的目录把docs/根目录下所有.md文件复制进去始终以英文版为翻译源因为英文版保持最新同时复制根目录的README.md与CONTRIBUTING.md翻译文件内容但不要改文件名也不要翻译以 [!开头的字符串这是 GitHub 专用的提示标记如 [!NOTE]、 [!TIP]提交 Pull Request随后在配套的网站仓库中把翻译文件复制到content/、data/、i18n/目录并翻译 YAML 文件中的值再为网站仓库提交 PR。结语FrankenPHP 的贡献流程围绕PHP 嵌入式运行时 Caddy 模块的双层架构展开Docker 开发镜像dev.Dockerfile解决了环境一致性问题go test -race与最小测试服务器internal/testserver覆盖了日常回归docker buildx bakedocker-bake.hcl支撑多平台产物而 GDB cgosymbolizer tmate 的组合则打通了 CI 环境下的段错误排查路径。掌握了 docs/fr/CONTRIBUTING.md 中的这条完整链路你就可以顺畅地提交 FrankenPHP 的 issue 复现报告与代码贡献了。【免费下载链接】frankenphp The modern PHP app server项目地址: https://gitcode.com/GitHub_Trending/fr/frankenphp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考