>_ DevTrendszh

语言

首页

语言

板块

前端 后端 移动端 DevOps AI / ML 游戏开发 区块链 嵌入式 安全
PHP

将 PHP 编译为原生二进制文件(无需解释器)

大约十五年前,Facebook 曾尝试用 HPHPc 编译器解决其单体应用的性能问题,该编译器将 PHP 转换为 C++。后来他们放弃了这一方案,转而采用 HHVM 虚拟机,而 PHP 8 引入了内置的 JIT 编译器。看起来纯 Ahead-Of-Time(AOT)编译器的概念似乎已经彻底成为历史。然而 Swoole 团队决定重新审视这一方向,并发布了 TypePHP 项目。

这是一个用 PHP 本身编写的完整 AOT 编译器。它将 PHP 8.4+ 源代码转换为 C++17,然后通过 GCC 或 Clang 编译成原生机器码。运行时无需操作码、无需 JIT 预热,也无需解释器。

该编译器是完全自托管的。phpc 工具从 PHP 源代码构建自身,编译器内部不包含任何 C 粘合代码。

TypePHP 的工作原理

编译分两个阶段进行。首先,分析器解析项目代码,收集类和函数的元数据,并构建完整的符号表。在第二阶段,函数体被翻译成 C++17。在热路径中,编译器生成快速的静态 C++ 代码,而对于反射或系统函数调用等动态构造,它通过 PHPX 层连接到 Zend 运行时。

输出可以是三种格式之一:

  • 可执行文件(.bin)。用于控制台工具和守护进程的独立文件,需要一个入口点 main()。
  • PHP 扩展(.so/.dll)。可加载到标准 PHP 中的常规 .so 或 .dll 模块。
  • 动态库(.a/.so)。包含生成的 .h 文件的二进制文件,可供其他项目调用。
  • WASI 组件,用于在 WebAssembly 环境中运行。

语法上的变化

TypePHP 并不试图支持标准 PHP 的所有动态特性。创作者们在需要最大性能的地方押注于严格类型化。

原生标量类型

declare(strict_types=1) 指令告诉编译器将 int、float 和 bool 直接映射到 C++ 类型(int64_t、double、bool)。使用这种类型的变量在函数执行过程中不能再突然改变类型。但处理器运行的是纯机器指令,无需解包 zval。

构建命令:

严格类型化的容器

常规 PHP 数组是通用的,但因哈希表而内存消耗大且速度慢。TypePHP 添加了 Vec、Map、Set 和 HashMap 结构。

在开发者测试中,使用 Vec 的循环更新元素耗时 6.4 秒,而启用 JIT 的常规 PHP 数组耗时 67.6 秒。速度实际上与手写的 C++ vector(6.2 秒)相当。

基元类型上的方法

不再使用一堆函数如 strlen()、substr() 或 strpos(),你可以直接在基元类型上调用方法。编译器在构建时解析这类调用,并将其转换为直接的 C 函数调用,无需虚表开销:

通过属性生成模板代码

为了避免手动编写大量 getter 和 setter,TypePHP 在编译期间处理自定义属性:

#[With] 属性生成一个克隆对象、更改字段并返回新实例的方法。这对于不可变的 DTO 很方便。

直接 C++ 集成

如果某个算法在 PHP 中缺失,你可以用 C++ 编写并放在旁边。通过带有空体的 stub 文件进行链接:

基准测试中的性能

根据作者在 phphp-bench 仓库的标准综合测试中的测量结果(启用 -O3 标志的 Mandelbrot 和 Fannkuch):

  • Mandelbrot 在 0.603 秒内完成,而标准解释器需要 5.034 秒(约 8 倍加速);
  • Fannkuch 在 2.021 秒内完成,而标准解释器需要 13.045 秒(6.5 倍加速)。

这些数字对于数学和分支的 AOT 编译来说是预期的。在实际 Web 应用中,大部分时间花在 I/O 和数据库操作上,所以改进会更有限,但对于计算任务和后台工作来说,差异是明显的。

局限性和权衡

目前还无法将现有的 Laravel 或 Symfony 项目移植到 TypePHP。有一些严格的规则:

  • 全局作用域中禁止可执行代码——所有代码必须位于函数或方法内。
  • 需要 PHP 8.4 或 8.5 以及编译后的 libphp 库(embed SAPI)来构建二进制文件。
  • 需要 GCC 9+ 支持 C++17、CMake 以及用于精确计算的 GMP/MPFR 库。
  • 一些动态语言特性(如自由类型切换或复杂引用)故意不被支持。

typephp.json 配置文件有助于管理大型项目中的依赖项和优化标志:

谁将从这个项目中受益

TypePHP 正在积极开发中。目前在 GitHub 上的星标数不到一千,但该项目由经验丰富的 Swoole 团队支持。

如果需要以下场景,尝试这个项目是有意义的:

  • 构建轻量级 CLI 工具或微服务作为单个二进制文件,无需在目标服务器上安装 PHP。
  • 在向客户本地交付时隐藏应用程序源代码,因为二进制文件比字节码更难反编译。
  • 编写包含大量计算的 PHP 扩展,而无需深入了解 C 和 Zend API。
  • 加速隔离的计算模块,如解析器、数据打包器或评分算法。

要开始使用,只需克隆仓库,通过 php build.php 构建测试脚本,然后查看 build 目录中生成的 C++ 代码。

相关项目