Swoole 的 typephp:让 PHP 编译成原生二进制的自举实验

2026 年 8 月 26 日,Swoole 团队开源了一个叫 typephp 的项目。它的描述只有一句话:

Swoole 的 typephp:让 PHP 编译成原生二进制的自举实验

PHP 的第三条路

2026 年 8 月 26 日,Swoole 团队开源了一个叫 typephp 的项目。它的描述只有一句话:

Compile PHP source code into native machine code ahead of time.

翻译过来就是:把 PHP 代码提前编译成原生机器码。不是字节码缓存(OPcache),不是 JIT(HHVM),是真正的 AOT——PHP 源码 → C++17 → 原生可执行文件。

这件事本身不新鲜。新鲜的是:typephp 是用 PHP 写的,而且能编译自己

自举:编译器的终极考试

在编译器世界有一个词叫"自举"(self-hosting)——编译器能编译自己的源码。这是编译器成熟度的终极测试。

C 编译器用 C 写,Go 编译器用 Go 写,Rust 编译器用 Rust 写。这些语言在 1.0 版本发布前都要完成自举——用自己的编译器编译自己的源码,产出能用的二进制。

PHP 从来没有过自举的编译器。原因很简单:PHP 是解释型语言,运行时是 Zend Engine,执行的是 opcode(字节码)。PHP 的"编译"只是把源码解析成 opcode 数组,运行时还是解释执行。这就像 Python 的 .pyc 文件——只是加速了加载,没有改变执行方式。

typephp 改变了这一点。它的编译器 tpc 是用 PHP 写的,但编译后的 tpc 是原生二进制。编译流程是:

PHP 源码(tpc 自己的源码)
    ↓ typephp 编译
C++17 代码
    ↓ 系统 C++ 编译器
原生 tpc 二进制

这个二进制能再编译其他 PHP 代码。这就是自举——PHP 第一次有了能编译自己的原生编译器

技术路线:PHP → C++ → 原生

typephp 的编译流程分三步:

第一步:解析 + 收集声明

PHP source + .stub.php declarations + optional C/C++ sources
    ↓
parse, validate, and collect declarations

这一步建立完整的符号模型,但不分配运行时缓存 ID。常量和默认值保留 AST 形式,等所有符号都收集完再处理。

第二步:降级到 C++17

    ↓
lower function bodies and constants to C++17

这一步把 PHP 的动态语义翻译成 C++ 的静态语义。int 变成 int64_tfloat 变成 doublebool 变成 bool。动态值(比如关联数组)通过 PHPX 和 Zend 运行时互操作。

第三步:编译成原生产物

    ↓
native compiler + reusable object/PCH caches
    ↓
executable | PHP extension | shared library | WASI component

这一步调用系统的 C++ 编译器(gcc/clang/MSVC),生成四种产物之一:可执行文件、PHP 扩展、共享库、WASI 组件。

三种产物,一个代码库

typephp 最有意思的设计是:同一份 PHP 代码可以编译成三种不同的原生产物

1. 可执行文件(bin)

tpc build --target=bin myapp.php
# 产出: myapp (原生可执行文件)

这是最直接的用法。PHP 代码变成一个不依赖 PHP 运行时的二进制。部署时不需要装 PHP,不需要装 Composer 依赖,一个文件搞定。

2. PHP 扩展(ext)

tpc build --target=ext mylib.php
# 产出: mylib.so (PHP 扩展)

把 PHP 代码编译成 PHP 扩展,然后在其他 PHP 项目里 dl('mylib.so') 加载。这相当于把热路径代码用 C++ 重写,但源码还是 PHP。

3. 共享库(lib)

tpc build --target=lib mylib.php
# 产出: libmylib.so (C 共享库)

把 PHP 代码编译成 C 共享库,可以被其他语言(Python、Go、Rust)通过 FFI 调用。这意味着 PHP 可以成为"系统级库"的编写语言——这在以前是不可想象的。

类型系统:PHP 语法,C++ 语义

typephp 的核心创新是:在保持 PHP 语法的同时,引入编译时类型信息

// 传统 PHP
function add($a, $b) {
    return $a + $b;
}

// typephp
function add(int $a, int $b): int {
    return $a + $b;
}

第二种写法在传统 PHP 里只是类型提示(运行时检查),在 typephp 里会被编译成:

int64_t add(int64_t a, int64_t b) {
    return a + b;
}

没有运行时类型检查,没有 zval 转换,没有 opcode 解释。就是两个整数相加,和手写 C++ 一样快。

更有意思的是容器类型:

// typephp 的强类型数组
$arr = std::vector<int>([1, 2, 3, 4, 5]);
$arr->push(6);

这会被编译成 std::vector,比 PHP 原生数组快 10 倍。因为 PHP 数组实际上是有序哈希表,每次访问都要算哈希;而 std::vector 是连续内存,直接索引。

诚实的"子集"策略

typephp 最让人欣赏的一点是它的诚实。README 里明确写着:

TypePHP intentionally supports a defined, testable subset of PHP rather than claiming drop-in compatibility with every dynamic PHP program.

它不支持所有 PHP 特性。有些动态特性(比如 extract()variable variables、运行时修改类定义)和 AOT 编译天然冲突,被列在 不兼容特性文档 里。

这种诚实很重要。很多"把 X 语言编译成 Y"的项目(比如把 Python 编译成 C++ 的 Cython、把 JS 编译成 WebAssembly 的 AssemblyScript)都死在了"声称完全兼容"上——一旦声称完全兼容,用户就会拿生产代码来试,然后发现 90% 的库不能用,项目就凉了。

typephp 的策略是:明确告诉你哪些能用,哪些不能用。能用的是强类型代码、数值计算、算法密集型逻辑。不能用的是高度动态的元编程。这和 TypeScript 的思路一样——不是替代 JavaScript,而是给愿意写类型注解的人一个更快的选项。

Swoole 的角色:为什么是他们做这件事

Swoole 是 PHP 生态里做异步运行时的团队,他们的 swoole 扩展让 PHP 能做协程、TCP 服务、WebSocket。现在他们做 typephp,逻辑是连贯的:

  • swoole 扩展:让 PHP 能做异步 I/O(解决并发问题)
  • typephp:让 PHP 能编译成原生代码(解决性能问题)
这两个方向加起来,PHP 就有了对抗 Go 和 Rust 的本钱——异步运行时 + 原生编译。当然,typephp 还在早期阶段,不能和 Go 的编译器或 Rust 的 LLVM 优化比。但它的存在本身就说明:PHP 生态不再满足于"够用就行"

和其他 AOT 方案的对比

方案语言产物自举类型系统
OPcachePHPopcode 缓存N/A动态
HHVM/HackPHP 方言JIT 执行渐进式
PyPyPythonJIT 执行是(RPython)动态
CythonPythonC 扩展渐进式
typephpPHP原生二进制渐进式
typephp 的独特之处是:它是唯一一个用被编译语言本身写的 AOT 编译器。Cython 用 Python 写但编译成 C 扩展,不能自举。HHVM 用 C++ 写,编译 PHP 但不产出独立二进制。typephp 用 PHP 写,编译 PHP,产出独立二进制——这是完整的自举闭环。

限制和未来

typephp 不是银弹:

  • 不是所有 PHP 代码都能编译。动态特性(evalvariable variablesextract)不支持。
  • 不是所有 PHP 扩展都能互操作。PHPX 覆盖了 Zend API,但第三方扩展的 C API 各不相同。
  • 编译时间不短。AOT 编译需要调用 C++ 编译器,大型项目可能需要几分钟。
  • 生态为零。没有 Composer 包支持 typephp 的类型系统,没有 IDE 插件,没有调试器。
但这些限制恰恰是它的定位:不是替代 PHP,而是给性能敏感的代码一个原生编译的选项。你可以把热路径函数用 typephp 编译成扩展,其他代码还是用普通 PHP。这种"渐进式编译"的思路和 Cython 一样——不要求你重写整个项目,只要求你标注关键函数的类型。

一个更大的问题:PHP 还需要 AOT 吗

这是最根本的问题。PHP 的性能瓶颈通常不在 CPU,而在 I/O——数据库查询、缓存、HTTP 请求。这些用 Swoole 的协程已经能解决。typephp 解决的是 CPU 密集型场景:图像处理、加密、数值计算、机器学习预处理。

这些场景在 PHP 生态里占比不大。但 typephp 的价值不在于"让 PHP 更快",而在于让 PHP 能进入它以前进不了的领域

  • 写一个 PHP 扩展,不需要学 C
  • 编译成共享库,给 Python/Go 调用
  • 打包成单二进制,部署到没有 PHP 的环境
这些场景以前需要换语言,现在可以在 PHP 生态内完成。这对 PHP 社区的意义远大于性能数字——它在扩展 PHP 的边界


项目地址github.com/swoole/typephp

官方文档swoole.com/aot/docs

Laravel News 报道laravel-news.com/typephp-compile-php-native-binaries

暂无表态

想参与讨论或点赞?登录后使用完整功能

讨论回复(1)

用 PHP 写了个编译器,把 PHP 编成 C++,再拿它把自己编译一遍。蛇吃尾巴,吃圆了。README 原话:written entirely in PHP, fully self-hosting,连一行 C 胶水都不留。我最欣赏的倒是个负面的决定——明说只支持 "a defined, testable subset",eval 和变量变量一律挡在门外。前辈们死在"号称全兼容"上的够多了,主动认怂反而显得能活。顺手算了笔账:PHP 数组是有序哈希表,取个值得先过一遍哈希;std::vector 连续内存直接下标,README 说快到 10 倍,我信,这不是魔法,是缓存行。至于 PHP 需不需要它——I/O 归 Swoole 管,CPU 密集的活以前只能换语言,现在多一个选项。挺好。

暂无表态
合作

智谱 GLM-5 已上线

在智谱开放平台 BigModel.cn 打造 AI 应用。新一代旗舰模型 GLM-5 在推理、代码、智能体综合能力达到开源模型 SOTA。

领取 2000万 Tokens