FrankenPHP原生支持Windows了吗?

摘要:FrankenPHP 原生支持 Windows 了 FrankenPHP 是什么 FrankenPHP 是一个基于 Caddy 和 PHP 构建的现代 PHP 应用服务器,目标是简化 PHP 应用的运行与部署。它既可以作为传统 PHP 应用
FrankenPHP 原生支持 Windows 了 FrankenPHP 是什么 FrankenPHP 是一个基于 Caddy 和 PHP 构建的现代 PHP 应用服务器,目标是简化 PHP 应用的运行与部署。它既可以作为传统 PHP 应用的运行环境,也提供了 Worker Mode、Hot Reloading 等更偏现代化的能力,因此这两年在 PHP 社区里关注度一直不低。 FrankenPHP 现已正式提供官方 Windows 支持,并立即可用。 自项目发布以来,Windows 原生支持一直是 FrankenPHP 社区呼声最高的需求之一。现在,这项能力已经正式落地。也就是说,FrankenPHP 已经可以在 Windows 上原生运行,并实现 100% 兼容,包括 Worker Mode、Hot Reloading 等核心特性。 性能表现 这次支持并不只是“能用”,性能表现也相当可观。社区已经给出了一些早期基准测试结果。 有用户在同一台 Windows Server 2022 机器上,将 FrankenPHP 与一个已经过优化的 Nginx/PHP-FPM 环境进行了对比。结果很直接:仅仅切换服务器运行时,就获得了 3.6 倍性能提升,增幅超过 260%。 此外,@henderkes 提供的一组更完整的基准测试,也进一步验证了 FrankenPHP 在 Windows 原生环境下、不同工作负载中的性能收益。 不过需要说明的是,原生 Windows 支持虽然已经足够快,在开发环境以及很多生产负载下也足够方便,但如果目标是追求更高的极限吞吐量,那么通过 WSL 运行 FrankenPHP 仍然更有优势,因为 Linux 在底层 I/O 和网络架构上依旧更强。如果生产环境允许,优先选择 Linux 仍然是更稳妥的方案。 难点:两个编译器体系的冲突 为什么这件事花了这么久? 实际上,此前已经有开发者尝试把 FrankenPHP 移植到 Windows。但除了常见的跨平台问题,例如文件路径和文件系统差异,更麻烦的是一个底层且结构性的兼容问题。 问题的核心可以概括为下面几点: FrankenPHP 是一个 Go 库,它通过 CGO 调用 PHP 的 libphp Windows 上的官方 PHP 构建使用 Visual Studio(MSVC)编译,以保证性能和稳定性 但 Go 的 CGO 在 Windows 上长期不支持 Visual Studio,而是只支持 MinGW(GCC) 这就留下了一个巨大的兼容性鸿沟:两边根本无法直接链接在一起 解决路径 围绕这个问题,项目曾尝试过几种方案,但最终都没有走通。 方案一:让 Windows 版 PHP 支持 GCC 第一种思路,是给 PHP 打补丁,让 Windows 版 PHP 支持 GCC 编译。但 PHP 维护者并不希望为此引入额外复杂度,这一点并不难理解。另一方面,项目本身也希望直接使用官方二进制,以保证稳定性并避免生态分裂。 因此,依赖 Visual Studio(MSVC)之外的其他编译器并不可行。毕竟,MSVC 是 PHP 官方唯一支持的 Windows 编译器。 方案二:“Frankenstein” 构建方案(llvm-mingw) 第二种思路是折中方案:使用 llvm-mingw 编译 FrankenPHP,再把它链接到官方 Visual Studio 编译的 PHP。 这个方案最终失败,原因是 标准库不匹配。 当你把 MinGW 编译出来的二进制(使用 msvcrt.dll 或自己的运行时)与 MSVC 编译出来的二进制(使用 ucrt / vcruntime)混在一起时,就会遇到严重问题。比如一侧分配内存(malloc),另一侧去释放;或者尝试跨边界传递文件描述符,程序都会直接崩溃。 本质上,它们说的是两种不同方言的 “C”。 突破点:Go 1.26 与 clang 最终,项目找到了更合理的路径:为 CGO 增加对 Visual Studio 提供的 Clang/LLVM 前端的支持。 可以简单理解为,Visual Studio 自带一套 Clang,它可以作为 MSVC 编译器(cl.exe)的替代实现来工作。它接受 CGO 更适配的 GCC 风格参数,同时底层又使用微软的 STL 和运行时库。 也就是说,它结合了两边的优点。 在调研现有方案、准备给 Go 提交补丁的过程中,项目方还发现 Google 其实已经提交过一份非常关键、但几乎没有公开说明的实现,处理的正是这个问题。 这份补丁最终进入了 Go 1.26。
阅读全文