编程 PHP也能Native AOT编译了!Swoole-Compiler让PHP代码直接变成机器码,性能提升150倍

2026-04-23 16:03:56 +0800 CST views 8

PHP也能Native AOT编译了!Swoole-Compiler让PHP代码直接变成机器码,性能提升150倍

2026年4月22日,Swoole 团队正式发布了 Swoole-Compiler v4 的 Native AOT 编译器,将 PHP 语言带入了"原生编译"时代。

这不是 Swoole 第一次让 PHP 变快——但这是第一次,让 PHP 直接"消失"在编译后的二进制里。

长期以来,PHP 被认为是"性能差"的语言。即使用了 OPcache + JIT,在密集计算场景下仍然无法与 Rust、Golang 等编译型语言相提并论。

Swoole-Compiler Native AOT 编译器彻底改写了这个结论:将 PHP 代码直接编译为原生机器指令,斐波那契数列测试中性能提升 150 倍,与 Rust、Golang 站在了同一水平线。

这意味着什么?

PHP 开发者不需要学 Rust,不需要重写项目,只需要用 AOT 编译器重新编译一次,现有 PHP 代码就能获得与编译型语言相当的执行效率。

一、为什么 PHP 一直"慢"?

要理解 AOT 编译的价值,先要理解 PHP 为什么"慢"。

解释型语言的宿命

PHP 是解释型脚本语言。每次执行 PHP 代码时,都需要经过以下流程:

  1. 词法分析:将 PHP 源代码转换为 token
  2. 语法分析:将 token 解析为 AST(抽象语法树)
  3. 编译:将 AST 编译为 Zend OPcode(中间指令)
  4. 解释执行:ZendVM 逐条执行 OPcode

这个流程在每次请求时都会重复执行——即使代码从未改变。

OPcache:解决了重复编译,但没有解决执行

PHP 7 引入的 OPcache 扩展,通过将编译后的 OPcode 缓存到内存中,解决了重复编译的问题。但执行阶段并没有变快——ZendVM 仍然要逐条"解释"OPcode。

JIT:让解释执行变快,但仍然受限

PHP 8 引入的 JIT(Just-in-Time)编译器,将热点 OPcode 动态编译为机器码,显著提升了执行效率。但 JIT 有两个根本局限:

  • 启动开销:JIT 需要在运行时分析热点代码,冷启动时没有加速
  • 内存开销:JIT 编译的机器码需要占用额外内存

更重要的是,JIT 优化的是"运行时",但 PHP 的执行框架本身仍然是一台虚拟机。

性能的"玻璃天花板"

用斐波那契数列测试可以看到:

执行方式计算 fib(40) 时间
PHP ZendVM(无 JIT)14.82 秒
PHP ZendVM + JIT2.37 秒
AOT 编译后0.11 秒

从 14.82 秒到 0.11 秒,AOT 编译器实现了 135 倍的加速,比 JIT 快了 21 倍。

这不是微优化,这是数量级的跃升。

二、Native AOT 编译:绕过虚拟机,直达机器码

什么是 AOT 编译?

AOT(Ahead-of-Time,预先编译)是一种编译策略:在程序运行之前,就把源代码编译为机器码。

与 JIT 的区别在于:

  • JIT:运行时编译,需要运行时环境(PHP 本身)
  • AOT:编译时完成,不需要运行时环境,生成独立的二进制可执行文件

Swoole AOT 的工作原理

Swoole-Compiler AOT 编译器的工作流程:

PHP 源代码 → [clang-format 格式化] → C++ 中间代码 → [g++ 编译] → 原生二进制

具体步骤:

1. 准备阶段(prepare)
扫描 PHP 源代码,解析语法结构,生成编译器内部表示。

2. 转换阶段(convert)
将 PHP 代码转换为 C++ 代码。生成的 C++ 代码调用 PHPX 库,PHPX 是 ZendPHP 提供的 C++ 兼容层,负责处理 PHP 的类型系统、内存管理、函数调用等底层机制。

3. 编译阶段
调用系统 C++ 编译器(g++)将 C++ 代码编译为原生二进制文件。编译过程支持多任务并行(-j 参数),充分利用多核 CPU。

与 HHVM、KPHP 的根本区别

过去也有将 PHP 编译为原生代码的项目,最著名的是 Facebook 的 HHVM 和 VKontakte 的 KPHP。但它们的共同问题是:用另一个实现替代了官方 PHP 解释器。

这带来了严重的兼容性问题:

  • 不支持某些 PHP 语法特性
  • 不支持某些 PHP 扩展
  • 与 Composer、autoload 等生态工具不兼容

Swoole AOT 编译器采用了完全不同的路线:

直接使用 ZendPHP 的底层库,通过 PHPX 库作为兼容层,在 ABI 层面与 PHP 完全互通。

这意味着:

  • ✅ 可以调用所有 PHP 扩展的内置函数、类和常量
  • ✅ 支持 evalincluderequire 等动态脚本执行
  • ✅ 支持 Composer,支持 autoload
  • ✅ 可以动态调用第三方 Composer 包提供的函数和类

AOT 编译器并不是 PHP 的另一个实现,而是 PHP 生态的原生编译加速器

三、性能实测:斐波那契 150 倍,PI 计算 72 倍

斐波那契数列测试

<?php
function fib(int $n): int {
    if ($n == 1 || $n == 2) return 1;
    return fib($n - 1) + fib($n - 2);
}

function main(int $argc, array $argv): void {
    $n = $argv[2];
    $begin = microtime(true);
    echo fib($n) . "\n";
    echo "Time: " . (microtime(true) - $begin) . "\n";
}

编译命令:./swoole-compiler examples/fib.php -O3

执行结果对比:

执行方式fib(40) 耗时相比 ZendVM
PHP ZendVM(无 JIT)14.82 秒1x
PHP ZendVM + JIT2.37 秒6.3x
AOT 编译(O3优化)0.11 秒135x

PI 值计算测试(Leibniz 公式)

<?php
use native_types;  // 启用原生类型,精度与 C++ 一致

function main() {
    $rounds = (int) file_get_contents("./rounds.txt", true);
    $stop = $rounds + 2;
    $x = 1.0;
    $pi = 1.0;
    for ($i = 2; $i <= $stop; $i++) {
        $x = -1.0 + 2.0 * ($i & 0x1);
        $pi += $x / (2 * $i - 1);
    }
    $pi *= 4.0;
    print $pi . "\ntime: " . (microtime(true) - $begin) . "\n";
}

执行结果对比(1亿轮迭代):

执行方式耗时加速比
PHP ZendVM6.52 秒1x
PHP ZendVM + JIT2.24 秒2.9x
AOT 编译0.09 秒72x

JIT vs AOT:不是竞争,是互补

有一点需要澄清:JIT 在某些场景下表现更好(尤其是 PHP 自带的 bench.php 测试),原因是 OPcache 的死代码消除优化器会移除未实际执行的代码。

这说明 AOT 和 JIT 是互补的技术:

  • JIT:适合 Web 场景的动态请求,热点代码即时优化
  • AOT:适合 CLI 工具、批量处理、科学计算等固定代码场景

四、C++ 与 PHP 的无缝互调用:素数计算的性能飞跃

AOT 编译器最有想象力的功能,是允许在 PHP 代码中直接调用 C++ 函数,两者一起编译为单个可执行文件。

这解决了一个长期困扰 PHP 开发者的难题:如何用高性能 C++ 代码处理 PHP 的密集计算?

素数计算的性能对比

用 PHP 数组存储 1000 万个布尔值来筛选素数:

// 纯 PHP 实现
$isPrime = array_fill(0, $limit + 1, true);

PHP 的数组是哈希表,即使存储一个布尔值,也至少占用 16 字节。存储 1000 万个值需要 40GB+ 内存

而用 C++ 的 std::vector<bool>(位图)只需要 120MB 内存

AOT 编译器的互调用设计,让 PHP 开发者可以直接使用 C++ 的高效数据结构:

PHP 代码(调用 C++ 函数):

// 使用 C++ vector 替代 PHP 数组
$isPrime = vector_new($limit + 1, true);
vector_set($isPrime, 0, false);
vector_set($isPrime, 1, false);

// 使用 C++ 逻辑处理
for ($i = 2; $i * $i <= $limit; $i++) {
    if (vector_get($isPrime, $i)) {
        for ($j = $i * $i; $j <= $limit; $j += $i) {
            vector_set($isPrime, $j, false);
        }
    }
}

C++ 实现(.cc 文件):

#include <phpx.h>
using namespace php;

class VectorBox : public Box {
public:
    std::vector<bool> vec;
    VectorBox(size_t size, bool init) { vec.resize(size, init); }
    void checkOffset(Int offset) {
        if (offset >= vec.size()) {
            throwError("index[%ld] is out of range()", offset);
        }
    }
};

var php_vector_new(Int size, Bool init) { return {new VectorBox(size, init)}; }
Bool php_vector_get(var box, Int offset) {
    auto vecbox = box.toBox<VectorBox>();
    vecbox->checkOffset(offset);
    return vecbox->vec.at(offset);
}
void php_vector_set(var box, Int offset, Bool value) {
    auto vecbox = box.toBox<VectorBox>();
    vecbox->checkOffset(offset);
    vecbox->vec.at(offset) = value;
}

函数声明(.stub.php 文件):

<?php
function vector_new(int $size, bool $init = false): mixed {}
function vector_get(mixed $vector, int $offset): bool {}
function vector_set(mixed $vector, int $offset, bool $value): void {}

类型映射规则简单清晰:

PHP 类型C++ 类型
intphp::Int
boolphp::Bool
arrayphp::Array
floatphp::Float
stringphp::Str
voidvoid

导出函数只需满足两个条件:php_ 为前缀 + 使用 PHP 类型作为参数和返回值

五、使用方法:3 步完成编译

1. 安装 Swoole-Compiler

从 Swoole 官方获取 AOT 编译器二进制文件,添加到系统 PATH。

2. 编写入口函数

AOT 编译器不支持"游离代码"(不在函数内的代码),所有代码必须放在函数内。

<?php
// 标准入口函数
function main(int $argc, array $argv): void
{
    echo "Hello World!\n";
    var_dump(PHP_VERSION);
}

3. 编译为二进制

# 编译为二进制可执行文件(默认模式)
./swoole-compiler app.php -O3 -o myapp

# 编译为 PHP 扩展(用于 PHP-FPM / Apache)
./swoole-compiler extension/ -m ext -o myextension.so

# 多任务并行编译(使用 8 核)
./swoole-compiler app.php -O3 -j 8

4. 优化输出大小

编译后的 ELF 文件可以通过 stripupx 压缩:

# 原始大小
-rwxrwxr-x 1 swoole swoole 377K main

# strip 后
-rwxrwxr-x 1 swoole swoole 39K main

从 377KB 压缩到 39KB,体积减少 90%。

六、语法限制:哪些 PHP 特性不能用?

AOT 是静态编译,某些依赖运行时动态特性的语法无法支持:

限制项说明替代方案
$$ 语法局部变量为编译器符号,运行时无法使用使用普通变量
extract() 函数无法在运行时创建局部变量手动赋值
yield/generator生成器语法静态编译不兼容使用 Fiber / Swoole 协程
多层 break/continue静态编译无法处理改为 gototry/catch
字面量字符串含 \0与 C++ 不兼容使用字符串拼接
参数数量不匹配调用动态执行阶段允许,编译阶段不允许严格参数数量
Property Hook 语法不支持使用传统 getter/setter
闭包引用参数运行时才能确定用值还是引用使用 refval() 显式指定

这些限制大多是 PHP 动态特性的"遗产",在实际项目中使用频率很低,绝大多数 PHP 代码库可以零修改直接编译。

七、native_types:让整数运算再快一步

PHP 的 int 类型有一个特殊设计:溢出时自动转为浮点数

这在大多数场景下是合理的(防止数据丢失),但在密集计算场景中牺牲了性能。AOT 编译器默认保持这个特性以兼容已有 PHP 代码。

如果你的代码不需要整数溢出保护,可以在文件顶部添加:

<?php
use native_types;  // 启用原生类型

function main() {
    $a = 10;
    $b = $a / 3;
    // $b = 3(截断),而不是 3.333...(浮点)
}

启用 native_types 后,整数和浮点类型使用 C++ 原生类型,执行速度更快,但溢出时直接丢弃精度而不是转为浮点。

八、适用场景:PHP 的新战场

AOT 编译器的价值不在于"替代 PHP",而在于拓展 PHP 的适用边界

1. CLI 工具与系统脚本

用 PHP 编写系统管理脚本、自动化工具,编译后分发给服务器,无需安装 PHP 运行时,部署极简。

2. 科学计算与数据处理

大规模数据处理、统计分析、算法验证,用 PHP 原型快速开发,AOT 编译后获得 C++ 级性能。

3. 高性能服务与微服务

对性能敏感的微服务组件(如数据清洗、消息队列消费者),用 PHP 快速开发,AOT 编译后达到生产级性能。

4. 游戏服务器逻辑

某些需要高性能但逻辑复杂的游戏逻辑(如 AI 决策、物品计算),可以用 PHP 编写,AOT 编译后部署。

5. 嵌入式与边缘计算

编译后的二进制文件体积小(strip 后仅 39KB),适合嵌入式设备和边缘计算场景。

九、总结:PHP 不再是"慢语言"

Swoole-Compiler Native AOT 编译器的发布,对 PHP 生态的意义是深远的:

对开发者:不需要学习新语言,不需要大规模重写,现有 PHP 技能和代码库直接获得编译型语言的性能。

对语言:PHP 不再只能在 Web 领域"脚本语言"的角色里打转。它有了进入高性能计算、系统工具、边缘计算领域的能力。

对生态:Composer、OPcache、Swoole 协程、AOT 编译……PHP 正在构建一个从 Web 脚本到高性能系统的完整工具体系。

150 倍的性能提升,不只是数字,是 PHP 从"解释型语言"走向"全能语言"的一次跃迁。


参考资料:

  • Swoole-Compiler 官方文档:https://github.com/swoole/swoole-src
  • PHPX 库:https://github.com/swoole/phpx
  • ZendPHP 官方:https://www.zend.com/enterprise/zend-php

推荐文章

在 Rust 生产项目中存储数据
2024-11-19 02:35:11 +0800 CST
js一键生成随机颜色:randomColor
2024-11-18 10:13:44 +0800 CST
PHP 如何输出带微秒的时间
2024-11-18 01:58:41 +0800 CST
如何在Vue3中定义一个组件?
2024-11-17 04:15:09 +0800 CST
使用 Go Embed
2024-11-19 02:54:20 +0800 CST
25个实用的JavaScript单行代码片段
2024-11-18 04:59:49 +0800 CST
PostgreSQL日常运维命令总结分享
2024-11-18 06:58:22 +0800 CST
CSS 媒体查询
2024-11-18 13:42:46 +0800 CST
windows下mysql使用source导入数据
2024-11-17 05:03:50 +0800 CST
html文本加载动画
2024-11-19 06:24:21 +0800 CST
Vue3中如何处理SEO优化?
2024-11-17 08:01:47 +0800 CST
淘宝npm镜像使用方法
2024-11-18 23:50:48 +0800 CST
服务器购买推荐
2024-11-18 23:48:02 +0800 CST
php内置函数除法取整和取余数
2024-11-19 10:11:51 +0800 CST
H5抖音商城小黄车购物系统
2024-11-19 08:04:29 +0800 CST
PHP 允许跨域的终极解决办法
2024-11-19 08:12:52 +0800 CST
程序员茄子在线接单