docs(readme): update documentation with comprehensive improvements

master
韩天峰 1 day ago
parent ced2ebb1ba
commit 022ca55ff0
  1. 301
      README-CN.md
  2. 335
      README.md

@ -6,9 +6,13 @@
**PHP 原生 AOT 编译器**
将 PHP 源码提前(AOT)编译为原生机器码,生成独立的可执行文件、PHP 扩展和静态库,
将 PHP 源码提前(AOT)编译为原生机器码,生成原生可执行文件、PHP 扩展和共享库,
同时保留你熟悉的 PHP 语法。
[![Tests](https://github.com/swoole/typephp/actions/workflows/tests.yml/badge.svg)](https://github.com/swoole/typephp/actions/workflows/tests.yml)
[![PHP 8.4–8.5](https://img.shields.io/badge/PHP-8.4--8.5-777bb4.svg)](https://www.php.net/)
[![License: GPL-3.0](https://img.shields.io/badge/License-GPL--3.0-blue.svg)](LICENSE)
</div>
---
@ -19,34 +23,64 @@ TypePHP 是一个 AOT(Ahead-Of-Time,提前编译)编译器,它把 PHP
再编译为原生机器码。与字节码缓存或虚拟机不同,它不会在运行时解释 opcode,
而是直接生成在 CPU 上运行的原生二进制。
它保留熟悉的 PHP 语法,同时引入编译期类型信息,让编译器为你的性能热点生成快速、
静态类型的 C++ 代码,而其余代码仍运行在久经考验的 Zend 引擎上。
它保留熟悉的 PHP 语法,同时引入编译期类型信息,让编译器为性能热点生成快速、
静态类型的 C++ 代码。动态 PHP 值、内置函数、反射和对象元数据继续通过 PHPX
与 Zend runtime 互操作;用户函数编译完成后不再以 Zend opcode 方式执行。
TypePHP **完全由 PHP 语言编写**,并且**完全自举**:`tpc` 编译器二进制就是
用 TypePHP 编译编译器自身的 PHP 源码得到的。整个自举链路是纯 PHP——编译器
本身没有任何 C 或 C++ 胶水代码。
TypePHP 仍在积极开发中。它提供的是边界明确、可测试的 PHP 子集,而不是宣称可以
无修改替代所有高度动态的 PHP 程序。在将现有项目迁移到 TypePHP 前,请先阅读
[兼容性模型](#兼容性模型)和[不兼容特性清单](docs/INCOMPATIBLE_PHP_FEATURES.md)。
## 工作原理
```text
PHP 源码 + .stub.php 声明 + 可选 C/C++ 源码
解析、校验并收集全部声明
将函数实现和常量表达式降级为 C++17
原生编译器 + 可复用对象/PCH 缓存
可执行文件 | PHP 扩展 | 共享库 | WASI Component
```
prepare 阶段只建立完整符号模型,不分配运行时 Cache ID。常量和声明默认值只保留
AST,待全部项目符号就绪后再在 convert 阶段解析。这一两阶段设计保证多文件构建和
编译器自举过程具有确定性。
## 特性
- **完全自举、纯 PHP 实现** —— TypePHP 编译器完全由 PHP 语言编写,并能自举:
`tpc` 编译编译器自身的源码,即可生成原生二进制。
- **真正的 AOT 编译** —— PHP 先降级为 C++17,再编译为原生机器码。无解释器、
无 opcode 缓存、无 JIT 预热。
- **三种构建模式** —— 同一份代码可编译为独立 `bin` 可执行文件、可加载的 PHP
`ext` 扩展,或 `lib` 静态库。
- **三种原生构建模式** —— 同一份代码可编译为原生 `bin` 可执行文件、可加载的
PHP `ext` 扩展,或可复用的 `lib` 共享库。
- **原生类型系统** —— `int`、`float`、`bool` 直接映射为 C++ 标量类型
(`int64_t`、`double`、`bool`),数值代码可获得数量级的性能提升。
- **高精度数值** —— `bigInt`(GMP)、`decimal`(libmpdec)、`bigFloat`(MPFR),
零开销算术运算。
提供强类型运算符和方法 API
- **强类型容器** —— `std::array`、`std::vector`、`std::map`、`std::ordered_map`,
元素类型在编译期确定;最高比 PHP 数组快 **10 倍**,性能与 C++ `std::vector` 相当。
- **通用方法(Universal Methods)** —— 在原生类型上直接调用方法
(`$s->upper()`、`$arr->contains()`、`$big->mul(2)`),零运行时派发开销。
(`$s->upper()`、`$arr->contains()`、`$big->mul(2)`);静态类型已知时在编译期
直接解析调用。
- **混合 C++ / PHP 编程** —— 在性能关键内核中直接调用 C++ 函数(反之亦然)。
- **编译期函数与关键词** —— `any()`、`refval()`、`objval()`、`expected()`、
`unexpected()`,以及 `toInt()`、`toString()`、`toArray()` 等。
- **编译期安全检查** —— `#[Immutable]` 只读契约和 `#[ArrayDef]` 数组结构元数据,
在编译期检查,零运行时开销。
- **编译期代码生成** —— `#[Getter]`、`#[Setter]`、`#[With]`、`#[Constructor]`、
`#[Printer]``#[Arrayable]` 根据属性声明生成类型安全的方法。
- **现代 PHP 支持** —— PHP 8.4 property hooks、非对称可见性、PHP 8.5
`clone()`-with 以及 `(void)` 丢弃表达式。
- **跨平台与 WASM** —— 面向 x86-64 和 ARM64 的 Linux、Windows、macOS 目标,
@ -60,7 +94,7 @@ TypePHP **完全由 PHP 语言编写**,并且**完全自举**:`tpc` 编译
| 编译目标 | 原生机器码 | 字节码 | 机器码(trace) |
| 启动 / 预热 | 无(已编译完成) | 每进程预热 | JIT 预热 |
| 类型驱动优化 | 编译期、全程序 | 无 | 有限,基于 trace |
| 独立可执行文件 | 支持 | 不支持 | 不支持 |
| 生成原生可执行文件 | 支持 | 不支持 | 不支持 |
| 源码保护 | 编译为机器码 | 字节码(可还原) | 字节码(可还原) |
| 性能确定性 | 是 | 否 | 否 |
@ -69,35 +103,40 @@ TypePHP **完全由 PHP 语言编写**,并且**完全自举**:`tpc` 编译
- **接近原生的性能。** 数值密集和容器密集的热点路径会编译为与 C++ 程序相同的机器码。
见下方[基准测试](#基准测试)。
- **源码保护。** 源码被编译掉——交付物是原生二进制,而不是可读的 PHP 文件。
- **零依赖部署。** 二进制模式生成单个自包含可执行文件,无需 PHP 运行时即可运行。
- **原生进程入口。** 二进制模式直接启动原生可执行文件,不需要 PHP CLI 或独立的
解释器进程。可执行文件仍会嵌入或链接 PHPX、`libphp` 及项目配置的原生库,部署包
中必须提供这些运行时依赖。
- **渐进式类型,真正带来收益。** 只在性能关键处添加 `use native_types`、`std::`
容器和类型声明,其余保持普通 PHP。
- **完整 PHP 生态互通。** 扩展模式以标准 PHP 扩展形式加载`php-fpm`
现有框架和工具链可继续使用
- **Zend 生态互通。** 扩展模式以标准 PHP 扩展形式加载,项目可以调用受支持的
内置函数,并显式声明依赖的其他 Zend 扩展
## 前置要求
- **PHP 8.4 – 8.5**,需包含 `embed` 模块(`libphp.so`)
- **PHP 8.4 – 8.5** CLI、开发头文件及 `php-config`
- 在类 Unix 系统构建二进制/共享库时,需要与 PHP 匹配的 **embed 库**(`libphp.so`)
- **GCC 9+**(或 Clang),支持 **C++17**
- **CMake 3.24+**
- **Composer 2**
- 高精度数学库:**GMP**、**MPFR**(libmpdec 已随 PHPX 内置)
```shell
# Ubuntu/Debian
sudo apt install libgmp-dev libmpfr-dev
sudo apt install build-essential cmake pkg-config libgmp-dev libmpfr-dev
# RHEL/CentOS/Fedora
sudo dnf install gmp-devel mpfr-devel
sudo dnf install gcc gcc-c++ cmake pkgconf-pkg-config gmp-devel mpfr-devel
# Arch Linux
sudo pacman -S gmp mpfr
sudo pacman -S base-devel cmake pkgconf gmp mpfr
```
> GMP 用于 `bigInt`,MPFR 用于 `bigFloat`。`decimal` 底层是 libmpdec,
> 已随 PHPX 内置,无需单独安装。
预览版目前以 **Linux** 为主要开发平台(推荐 Ubuntu 22.04)。Windows 和 macOS
打包通过同一入口点支持。
Linux 是主要开发和 CI 平台。编译器也提供 Windows、macOS、x86-64、ARM64 和
WASI 后端;具体主机能否构建某个目标,仍取决于 PHP embed、工具链和第三方库是否
可用。
## 安装
@ -119,11 +158,24 @@ vendor/bin/tpc.php project.yml
bin/tpc.php project.yml
```
### 从源码安装
```bash
git clone https://github.com/swoole/typephp.git
cd typephp
composer install
php bin/tpc.php --help
```
可以使用 `PHPX_HOME` 指向独立的 PHPX 源码或安装目录。`PHP_HOME` 可以指向 PHP
embed 安装前缀;在类 Unix 系统中,该目录应包含 `bin/php-config`、PHP 头文件和
`lib/libphp.so`
### 构建 `libphp.so`
`tpc` 需要以 `embed` SAPI 构建的 PHP。如果 Linux 上缺少 `libphp.so`
`tpc.php` 可以交互式下载 PHP 源码并自动构建。详见
[自动构建 libphp.so](docs/LIBPHP_INSTALLER.md)。
二进制和共享库构建需要 PHP 的 `embed` SAPI。如果 Linux 上缺少 `libphp.so`
`tpc.php` 可以交互式下载 PHP 源码并自动构建。PHP 扩展构建从宿主 SAPI 解析 Zend
符号,不能再加载第二份 `libphp`。详见[自动构建 libphp.so](docs/LIBPHP_INSTALLER.md)。
## 快速开始
@ -147,16 +199,17 @@ bin/tpc.php hello.php
./hello
```
输出:
输出示例(具体 PHP 版本和平台字符串取决于实际链接的运行时)
```
Hello World!
string(5) "8.4.x"
string(5) "8.x.x"
string(16) "Linux ..."
```
> 二进制模式需要全局 `main()` 函数。它可以声明为无参数,或
> `main(int $argc, array $argv)` 以接收命令行参数,且必须返回 `void`
> `main(int $argc, array $argv)` 以接收命令行参数,且必须返回 `void`。全局作用域
> 不允许可执行语句;可执行代码必须位于函数或方法内。
## 编译模式
@ -165,8 +218,8 @@ TypePHP 支持三种构建模式,通过 `-m` / `--mode` 选择:
| 模式 | 参数 | 输出 | 需要 `main()` | 典型用途 |
|---|---|---|---|---|
| 二进制 | `-m bin`(默认) | 可执行文件 | 是 | CLI 工具、常驻服务、独立应用 |
| 扩展 | `-m ext` | `.so` / `.dll` | 否 | `php-fpm` 上的 Web 应用、即插即用 PHP 扩展 |
| 库 | `-m lib` | 静态库 | 否 | 将编译后的代码嵌入其他项目 |
| 扩展 | `-m ext` | PHP `.so` / `.dll` | 否 | 将编译后的函数和类加载到 PHP SAPI |
| 库 | `-m lib` | 共享库及自动生成的 `.stub.php` | 否 | 在其他项目中复用编译后的 TypePHP API |
```bash
# 二进制(默认)
@ -175,12 +228,130 @@ bin/tpc.php app.php -o myapp
# PHP 扩展
bin/tpc.php extension/ -m ext -o my_extension
# 静态库
# 共享库,同时生成 mylib.stub.php
bin/tpc.php lib/ -m lib -o mylib
```
详见[编译模式](docs/COMPILATION_MODES.md)。
## 项目配置
多文件项目建议使用 `project.yml` 固化可复用的构建配置:
```yaml
name: myapp
mode: bin
php-version: "8.5"
optimize: 2
job: 8
build-dir: build
cxx-std: c++17
sources:
- src
- cpp-src
- path: src/php85
if: PHP_VERSION_ID >= 80500
- path: src/windows
if: PHP_OS_FAMILY == "Windows"
ignore:
- src/experimental
include-paths:
- native/include
defines:
- FEATURE_FAST_PATH=1
link-paths:
- native/lib
link-libs:
- curl
# Zend 扩展依赖,不是原生链接库。
# `extension-dependencies` 是等价长名称,两者不能同时使用。
ext-deps:
- pdo_mysql
- curl
```
路径以 YAML 文件所在目录为基准。source 可以是文件或目录;条件 source 支持
`PHP_VERSION`、`PHP_VERSION_ID` 和 `PHP_OS_FAMILY`。命令行参数优先于 YAML
中的同名配置。原生链接依赖应写入 `link-libs`;`ext-deps` 会生成
`ZEND_MOD_REQUIRED`,缺少所需 PHP 扩展时由 Zend 拒绝加载模块。
构建目录保存生成的 C++、依赖对象和预编译头缓存。复用同一个构建目录可以显著加快
增量构建;仅在确实需要重编 PHPX 公共对象时使用 `--force`
全部项目配置项及命令行优先级详见[编译器命令行](docs/COMPILER_CLI.md)。
## 兼容性模型
TypePHP 会在适合 AOT 编译的范围内保持 PHP 语法和运行行为,同时有一些明确限制:
- 全局作用域只允许声明,可执行语句必须位于函数或方法内;
- 二进制模式对 `main()` 使用严格签名;
- `use native_types` 会让标量声明使用固定原生存储,之后不能改为不兼容类型;
- 静态可确定的调用和属性会直接编译,受支持的动态操作则通过 PHPX/Zend runtime
fallback 执行;
- `.stub.php` 用于声明 C++ 或外部库 API,函数体必须为空,stub 文件禁止声明
`#[Native]` 类;
- 部分高度动态的引用、声明、闭包和反射模式仍明确不支持。
兼容性边界属于公共契约,同时有正向和负向测试保护。请以
[不兼容 PHP 特性清单](docs/INCOMPATIBLE_PHP_FEATURES.md)为当前准确列表,不要把
README 未提及的行为默认理解为已支持。
## 编译期 Attribute 与代码生成
TypePHP 在 class lowering 阶段消费内置的代码生成 Attribute。生成的方法保留属性
声明的类型,并与显式声明的方法一样参与名称冲突、继承关系和 final 方法检查。
| Attribute | 目标 | 生成的 API |
|---|---|---|
| `#[Getter]` | 实例属性,包括构造器提升属性 | `public function getName(): T` |
| `#[Setter]` | 可变实例属性,包括构造器提升属性 | `public function setName(T $name): void` |
| `#[With]` | 可变实例属性,包括构造器提升属性 | `public function withName(T $name): static`;克隆对象、修改副本并返回副本 |
| `#[Constructor]` | 普通实例属性声明 | 将属性加入自动生成的 public `__construct()` |
| `#[Printer]` | 具名类 | `public function __toString(): string` |
| `#[Arrayable]` | 具名类 | `public function toArray(): array` |
```php
<?php
#[Printer(fields: ['id', 'name'])]
#[Arrayable(fields: ['id', 'name'])]
final class User
{
#[Constructor, Getter, With]
public int $id;
#[Constructor, Getter, Setter]
public string $name = 'guest';
}
function main(): void
{
$user = new User(7);
$user->setName('Alice');
$copy = $user->withId(8);
echo $user->getId(); // 7
echo $copy->getId(); // 8
echo $user; // User(id=7, name=Alice)
echo $user->toArray()['name'];
}
```
未指定 `fields` 时,`#[Printer]` 和 `#[Arrayable]` 使用当前类自身的 public 实例
属性。位置参数写法 `#[Arrayable(['id'])]` 等价于
`#[Arrayable(fields: ['id'])]`
`#[Getter]`、`#[Setter]` 和 `#[With]` 不能用于 static 属性或带 property hook 的
属性;`#[Setter]` 和 `#[With]` 还会拒绝 readonly 属性。类中已经显式声明
`__construct()` 时不能使用 `#[Constructor]`,必填的构造属性必须位于带默认值的
属性之前。生成的方法名若与已有方法冲突,或覆盖继承而来的 final 方法,编译期会
直接报错。
## 使用示例
### 1. 原生类型 —— 编译期数值加速
@ -306,7 +477,7 @@ function main(): void
using namespace php;
var php_fast_sum(Int a, Int b) {
Int php_fast_sum(Int a, Int b) {
return a + b;
}
```
@ -314,7 +485,7 @@ var php_fast_sum(Int a, Int b) {
```php
<?php
// math.stub.php —— 声明 C++ 函数签名
function fast_sum(int $a, int $b): int;
function fast_sum(int $a, int $b): int {}
```
```php
@ -325,6 +496,10 @@ function main(): void
}
```
需要将 `math.cpp`、`math.stub.php` 和调用它的 PHP 源码加入同一个项目配置。
C++ 符号的 `php_` 前缀属于 TypePHP callable ABI;stub 函数只提供类型元数据,
不能包含实际实现。
详见[混合 C++/PHP](docs/MIXED_CPP_PHP.md)。
## 基准测试
@ -340,7 +515,12 @@ TypePHP 使用 `-O3` 运行 PHP 源码树自带的官方 `bench.php` 与
| `micro_bench.php`(总计) | 13.045 秒 | **2.021 秒** | 约 6.5× |
两项基准覆盖 PHP 语言核心性能——函数调用、对象属性访问、数组/哈希访问、
字符串处理、控制流等。完整逐项报告见 [`bench.txt`](bench.txt)。
字符串处理、控制流等。仓库内的测试源码为
[`examples/bench.php`](examples/bench.php)和
[`examples/micro_bench.php`](examples/micro_bench.php)。
这些数字是项目测量快照,不是性能保证。PHP 版本、编译器、CPU、优化参数和已启用
扩展都会影响结果;在用于部署决策前,应在同一机器上使用相同 workload 自行对比。
### std::array 对比 PHP 数组
@ -353,7 +533,7 @@ TypePHP 使用 `-O3` 运行 PHP 源码树自带的官方 `bench.php` 与
| `std::array`(TypePHP AOT) | **6.4 秒** |
| C++ `std::vector` | 6.2 秒 |
`std::array` 比 PHP 数组快约 **10 倍**,性能与手写 C++ 完全一致
在该 workload 中,`std::array` 比 PHP 数组快约 **10 倍**,并接近手写 C++ 结果
完整基准测试见 [Std 容器](docs/STD_CONTAINERS.md)。
## 命令行
@ -397,13 +577,20 @@ bin/tpc.php --wasm=browser app.php
| `-m`, `--mode <bin\|lib\|ext>` | 构建模式(默认 `bin`) |
| `-r`, `--run` | 构建成功后运行 |
| `-j`, `--job <num>` | 并行编译任务数(默认 `4`) |
| `-f`, `--force` | 不使用缓存,重新编译可复用 PHPX 对象 |
| `--build-dir <dir>` | 生成 C++ 与中间产物的目录 |
| `--dry` | 只生成 C++,跳过编译与链接 |
| `--php-version <8.4\|8.5>` | 接受的 PHP 语法版本 |
| `--cxx-std <ver>` | C++ 标准(如 `c++17`、`c++20`) |
| `--march <arch>` | 目标指令集(如 `native`) |
| `--target-platform <triple>` | 交叉编译目标 triple |
| `--lto` | 启用链接时优化 |
| `--sanitize <type>` | 启用 sanitizer(如 `address`) |
| `--profile` | 启用 Linux gperftools 性能分析 |
| `--format` | 使用 clang-format 格式化生成的 C++ |
| `--no-literal-strings` | 禁用字面量字符串表优化 |
| `--no-progress`, `--no-color` | 适合 CI 的输出控制 |
| `-I`, `-D`, `-L`, `-l` | 可重复指定的原生 include、define、库路径和链接库参数 |
运行 `bin/tpc.php --help` 查看权威的最新参数列表。详见
[编译器命令行](docs/COMPILER_CLI.md),包括 Bash 补全:
@ -412,6 +599,20 @@ bin/tpc.php --wasm=browser app.php
source <(./tpc --generate-completion=bash)
```
## 常见问题
- **缺少 `libphp.so`:** 安装或编译与当前 PHP 匹配的 embed SAPI,设置
`PHP_HOME`,或使用 `bin/tpc.php` 在 Linux 上提供的交互式安装流程。
- **找不到 PHPX:**`PHPX_HOME` 指向包含 `include/`
`lib/libphpx.so`(或对应平台文件)的 PHPX 安装目录,并在编译项目前先构建 PHPX。
- **启动崩溃或出现 ABI 错误:** PHP 头文件、`php-config`、`libphp` 和扩展 ABI
必须使用一致的 PHP 版本及 ZTS/NTS 模式,不能混用不同 PHP 构建产生的产物。
- **增量构建异常缓慢:** 固定使用同一个 `--build-dir`,以复用对象和 PCH 缓存。
当外层测试工具已经并行运行多个测试时,不要再设置过大的 `tpc -j`,避免并发数
相乘后造成 CPU 和内存争用。
- **使用 `bin/tpc.php` 可以编译,但自举 `tpc` 失败:** 必须用自举编译器复现。
自举执行可能暴露 PHP-hosted 编译器不会经过的动态调用或 ABI 路径。
## Python 桥接
TypePHP 内置一个 Python 工具子模块,复用 `tpc` 入口:
@ -427,6 +628,39 @@ TypePHP 内置一个 Python 工具子模块,复用 `tpc` 入口:
详见 [Python 工具子模块](docs/python/tools.md)。
## 开发与测试
安装开发依赖并运行编译器单元测试:
```bash
composer install
PHPX_HOME=/path/to/phpx vendor/bin/phpunit
```
PHPT 是端到端测试。必须先构建自举编译器,并显式传给测试工具;将 Zend PHP
可执行文件作为 `--compiler` 并不能验证实际交付的编译器:
```bash
PHPX_HOME=/path/to/phpx php bin/tpc.php project.yml --job 2 --no-progress
php run-tests.php -q -j8 --compiler ./tpc tests/compiler
```
静态分析与从测试源码生成的覆盖矩阵是两项独立检查:
```bash
composer analyse
php bin/analyze-test-coverage.php
php bin/analyze-test-coverage.php \
--format=markdown --output=build/test-coverage.md --strict
```
覆盖工具分别报告 PHP 版本 × 特性 × 正向编译 × 运行语义 × 负向诊断,并列出实际
出现的 php-parser AST 节点。它不会给出分母不明确的单一百分比。详见
[测试覆盖分析工具](docs/TEST_COVERAGE_ANALYZER.md)。
GitHub Actions 会在 PHP 8.4 和 8.5 上分别运行 PHPUnit 与自举 PHPT。修改编译器
内部规则或代码生成时应增加聚焦的 PHPUnit;运行输出或诊断可观察时还应增加 PHPT。
## 文档
- [快速入门](docs/QUICKSTART.md) —— 最小编译流程
@ -436,10 +670,15 @@ TypePHP 内置一个 Python 工具子模块,复用 `tpc` 入口:
- [原生类型](docs/NATIVE_TYPES.md) —— 原生标量类型
- [高精度类型](docs/HIGH_PRECISION_TYPES.md) —— BigInt / Decimal / BigFloat
- [Std 容器](docs/STD_CONTAINERS.md) —— 强类型容器
- [通用方法](docs/UNIVERSAL_METHODS.md) —— 零开销方法
- [通用方法](docs/UNIVERSAL_METHODS.md) —— 编译期方法解析
- [编译期函数](docs/COMPILE_TIME_FUNCTIONS.md) —— `any()`、`refval()`、`objval()` 等
- [混合 C++/PHP](docs/MIXED_CPP_PHP.md) —— C++/PHP 互操作
- [`#[Immutable]`](docs/IMMUTABLE.md) —— 编译期只读契约
- [`#[ArrayDef]`](docs/ARRAY_DEF.md) —— 强类型数组属性契约
- [Property hooks](docs/PROPERTY_HOOKS.md) —— PHP 8.4 hook 降级和运行时元数据
- [对象存储模型](docs/OBJECT_STORAGE_AND_PASSING_MODELS.md) —— Zend object、Box 与 Native class 边界
- [Generator](docs/YIELD_GENERATOR.md) —— 生成器降级与生命周期
- [测试覆盖分析工具](docs/TEST_COVERAGE_ANALYZER.md) —— AST 与特性证据矩阵
- [WASI 构建](docs/WASI_BUILD.md) —— WASI 目标
## 授权协议

@ -7,9 +7,13 @@
**A native AOT compiler for PHP**
Compile PHP source code into native machine code ahead of time — producing
standalone executables, PHP extensions, and static libraries — while keeping
native executables, PHP extensions, and shared libraries — while keeping
the PHP syntax you already know.
[![Tests](https://github.com/swoole/typephp/actions/workflows/tests.yml/badge.svg)](https://github.com/swoole/typephp/actions/workflows/tests.yml)
[![PHP 8.4–8.5](https://img.shields.io/badge/PHP-8.4--8.5-777bb4.svg)](https://www.php.net/)
[![License: GPL-3.0](https://img.shields.io/badge/License-GPL--3.0-blue.svg)](LICENSE)
</div>
---
@ -22,14 +26,45 @@ not interpret opcodes at runtime: it generates optimized native binaries that
run directly on the CPU.
It keeps familiar PHP syntax and adds compile-time type information, so the
compiler can emit fast, statically-typed C++ for your hot paths — while the
rest of your code continues to run on the battle-tested Zend engine.
compiler can emit fast, statically-typed C++ for hot paths. Dynamic PHP values,
internal functions, reflection, and object metadata continue to interoperate
with the Zend runtime through PHPX; user functions are not executed as Zend
opcodes after they have been compiled.
TypePHP is **written entirely in PHP** and is **fully self-hosting**: the `tpc`
compiler binary is built by compiling the compiler's own PHP source code with
TypePHP. The bootstrap chain is pure PHP — no C or C++ glue in the compiler
itself.
TypePHP is under active development. It intentionally supports a defined,
testable subset of PHP rather than claiming drop-in compatibility with every
dynamic PHP program. Read [Compatibility model](#compatibility-model) and the
[incompatible-feature list](docs/INCOMPATIBLE_PHP_FEATURES.md) before adopting
it for an existing application.
## How it works
```text
PHP source + .stub.php declarations + optional C/C++ sources
parse, validate, and collect declarations
lower function bodies and constants to C++17
native compiler + reusable object/PCH caches
executable | PHP extension | shared library | WASI component
```
The prepare phase builds the complete symbol model without allocating runtime
cache IDs. Constants and declaration defaults retain their AST until the
convert phase, where they are lowered after all project symbols are known.
This two-phase design keeps multi-file and self-hosted builds deterministic.
## Features
- **Self-hosting, written in PHP** — the TypePHP compiler is implemented
@ -37,19 +72,19 @@ itself.
source into a native binary.
- **True AOT compilation** — PHP is lowered to C++17, then to native machine
code. No interpreter, no opcode cache, no JIT warm-up.
- **Three build modes** — build a standalone `bin` executable, a loadable PHP
`ext` extension, or a `lib` static library from the same codebase.
- **Three native build modes** — build a native `bin` executable, a loadable
PHP `ext` extension, or a reusable `lib` shared library from the same codebase.
- **Native type system**`int`, `float`, and `bool` map directly to C++
scalar types (`int64_t`, `double`, `bool`) for orders-of-magnitude speedups
on numeric code.
- **High-precision numerics**`bigInt` (GMP), `decimal` (libmpdec), and
`bigFloat` (MPFR) with zero-overhead arithmetic.
`bigFloat` (MPFR), with typed operators and method APIs.
- **Strongly-typed containers**`std::array`, `std::vector`, `std::map`, and
`std::ordered_map` with compile-time element types; up to **10×** faster than
PHP arrays and on par with C++ `std::vector`.
- **Universal methods** — call methods directly on primitives
(`$s->upper()`, `$arr->contains()`, `$big->mul(2)`) with zero runtime
dispatch overhead.
(`$s->upper()`, `$arr->contains()`, `$big->mul(2)`); statically-known calls
are resolved directly at compile time.
- **Mixed C++ / PHP** — call C++ functions from PHP (and vice versa) for
performance-critical kernels.
- **Compile-time functions & keywords**`any()`, `refval()`, `objval()`,
@ -57,6 +92,9 @@ itself.
friends.
- **Compile-time safety**`#[Immutable]` read-only contracts and `#[ArrayDef]`
array-shape metadata, checked at compile time with zero runtime cost.
- **Compile-time code generation**`#[Getter]`, `#[Setter]`, `#[With]`,
`#[Constructor]`, `#[Printer]`, and `#[Arrayable]` generate type-safe methods
from property declarations.
- **Modern PHP support** — PHP 8.4 property hooks, asymmetric visibility,
PHP 8.5 `clone()`-with, and `(void)` discard expressions.
- **Cross-platform & WASM** — Linux, Windows, and macOS targets for x86-64 and
@ -71,7 +109,7 @@ itself.
| Compilation target | Native machine code | Bytecode | Machine code (trace) |
| Startup / warm-up | None (already compiled) | Per-process warm-up | JIT warm-up |
| Type-driven optimization | Compile-time, full-program | None | Limited, trace-based |
| Standalone executable | Yes | No | No |
| Native executable output | Yes | No | No |
| Source code protection | Compiled to machine code | Bytecode (reversible) | Bytecode (reversible) |
| Deterministic performance | Yes | No | No |
@ -82,38 +120,45 @@ itself.
[benchmark](#benchmark) below.
- **Source protection.** Your source is compiled away — shipped artifacts are
native binaries, not readable PHP files.
- **Zero-dependency deployment.** Binary mode produces a single self-contained
executable that runs without a PHP runtime.
- **Native process entry.** Binary mode starts directly from a native
executable and does not require the PHP CLI or a separate interpreter
process. The executable still embeds/links PHPX, `libphp`, and any configured
native libraries, which must be available in the deployment package.
- **Gradual typing that actually pays off.** Add `use native_types`, `std::`
containers, and type declarations only where performance matters; the rest
stays ordinary PHP.
- **Full PHP ecosystem interop.** Extension mode loads as a standard PHP
extension into `php-fpm`, so existing frameworks and tooling keep working.
- **Zend ecosystem interop.** Extension mode loads as a standard PHP extension,
and projects can call supported internal functions and require other Zend
extensions explicitly.
## Requirements
- **PHP 8.4 – 8.5** with the `embed` module (`libphp.so`)
- **PHP 8.4 – 8.5** CLI, development headers, and `php-config`
- The matching **PHP embed library** (`libphp.so`) for binary/shared-library
builds on Unix-like systems
- **GCC 9+** (or Clang) with **C++17**
- **CMake 3.24+**
- **Composer 2**
- High-precision math libraries: **GMP**, **MPFR** (libmpdec is bundled with PHPX)
```shell
# Ubuntu/Debian
sudo apt install libgmp-dev libmpfr-dev
sudo apt install build-essential cmake pkg-config libgmp-dev libmpfr-dev
# RHEL/CentOS/Fedora
sudo dnf install gmp-devel mpfr-devel
sudo dnf install gcc gcc-c++ cmake pkgconf-pkg-config gmp-devel mpfr-devel
# Arch Linux
sudo pacman -S gmp mpfr
sudo pacman -S base-devel cmake pkgconf gmp mpfr
```
> GMP powers `bigInt` and MPFR powers `bigFloat`. The `decimal` type is backed
> by libmpdec, which is bundled with PHPX — no separate install required.
The preview currently targets **Linux** as the primary development platform
(Ubuntu 22.04 recommended). Windows and macOS packaging is supported through
the same entry point.
Linux is the primary development and CI platform. The compiler also has
Windows, macOS, x86-64, ARM64, and WASI backends; availability of PHP embed,
toolchain, and third-party libraries still determines which target can be
built on a given host.
## Installation
@ -136,11 +181,26 @@ instead:
bin/tpc.php project.yml
```
### From source
```bash
git clone https://github.com/swoole/typephp.git
cd typephp
composer install
php bin/tpc.php --help
```
`PHPX_HOME` may point to a separate PHPX checkout or installation. `PHP_HOME`
may point to the PHP embed prefix; it must contain `bin/php-config`, PHP headers,
and `lib/libphp.so` on Unix-like systems.
### Building `libphp.so`
`tpc` requires a PHP built with the `embed` SAPI. If `libphp.so` is missing on
Linux, `tpc.php` can interactively download the PHP source and build it for
you. See [Automatic libphp.so build](docs/LIBPHP_INSTALLER.md).
Binary and shared-library builds require PHP's `embed` SAPI. If `libphp.so` is
missing on Linux, `tpc.php` can interactively download the PHP source and build
it for you. A PHP extension build resolves Zend symbols from the host SAPI and
must not load a second `libphp`. See
[Automatic libphp.so build](docs/LIBPHP_INSTALLER.md).
## Quick Start
@ -164,17 +224,19 @@ bin/tpc.php hello.php
./hello
```
Output:
Example output (the exact PHP version and platform strings depend on the linked
runtime):
```
Hello World!
string(5) "8.4.x"
string(5) "8.x.x"
string(16) "Linux ..."
```
> Binary mode requires a global `main()` function. It may be declared with no
> parameters, or as `main(int $argc, array $argv)` to receive command-line
> arguments, and must return `void`.
> arguments, and must return `void`. Top-level executable statements are not
> allowed; executable code belongs in a function or method.
## Compilation Modes
@ -183,8 +245,8 @@ TypePHP supports three build modes, selected with `-m` / `--mode`:
| Mode | Flag | Output | Needs `main()` | Typical use |
|---|---|---|---|---|
| Binary | `-m bin` (default) | Executable | Yes | CLI tools, long-running services, standalone apps |
| Extension | `-m ext` | `.so` / `.dll` | No | Web apps on `php-fpm`, drop-in PHP extension |
| Library | `-m lib` | Static library | No | Embedding compiled code into other projects |
| Extension | `-m ext` | PHP `.so` / `.dll` | No | Loading compiled functions/classes into a PHP SAPI |
| Library | `-m lib` | Shared library plus generated `.stub.php` | No | Reusing a compiled TypePHP API from another project |
```bash
# Binary (default)
@ -193,12 +255,141 @@ bin/tpc.php app.php -o myapp
# PHP extension
bin/tpc.php extension/ -m ext -o my_extension
# Static library
# Shared library; also generates mylib.stub.php
bin/tpc.php lib/ -m lib -o mylib
```
See [Compilation modes](docs/COMPILATION_MODES.md) for details.
## Project configuration
For multi-file projects, keep repeatable build settings in `project.yml`:
```yaml
name: myapp
mode: bin
php-version: "8.5"
optimize: 2
job: 8
build-dir: build
cxx-std: c++17
sources:
- src
- cpp-src
- path: src/php85
if: PHP_VERSION_ID >= 80500
- path: src/windows
if: PHP_OS_FAMILY == "Windows"
ignore:
- src/experimental
include-paths:
- native/include
defines:
- FEATURE_FAST_PATH=1
link-paths:
- native/lib
link-libs:
- curl
# Zend extension requirements, not native linker libraries.
# `extension-dependencies` is the equivalent long name; do not use both.
ext-deps:
- pdo_mysql
- curl
```
Paths are resolved relative to the YAML file. A source entry may be a file or
directory; conditional entries support `PHP_VERSION`, `PHP_VERSION_ID`, and
`PHP_OS_FAMILY`. CLI arguments override their YAML counterparts. Native linker
dependencies belong in `link-libs`; `ext-deps` writes `ZEND_MOD_REQUIRED`
entries so Zend can reject loading when a required PHP extension is missing.
The build directory contains generated C++, dependency objects, and the
precompiled-header cache. Reusing it makes incremental builds much faster;
use `--force` only when the reusable PHPX objects must be rebuilt.
See [Compiler CLI](docs/COMPILER_CLI.md) for all project keys and command-line
precedence rules.
## Compatibility model
TypePHP follows PHP syntax and runtime behavior where they are compatible with
ahead-of-time compilation, but it also makes several deliberate restrictions:
- global scope is declaration-only; executable statements must be inside a
function or method;
- binary mode has a strict `main()` signature;
- `use native_types` opts scalar declarations into fixed native storage, so a
value cannot later change to an incompatible type;
- statically-known calls and properties are compiled directly, while supported
dynamic operations use PHPX/Zend runtime fallbacks;
- `.stub.php` files declare C++ or imported-library APIs and must contain empty
bodies; `#[Native]` classes are not permitted in stub files;
- some highly dynamic reference, declaration, closure, and reflection patterns
remain intentionally unsupported.
The compatibility boundary is part of the public contract and has both
positive and negative tests. Consult
[Incompatible PHP features](docs/INCOMPATIBLE_PHP_FEATURES.md) for the current,
specific list instead of assuming that absence from this README means support.
## Compile-time attributes and code generation
TypePHP consumes its built-in code-generation attributes while lowering the
class. The generated methods retain the declared property types and take part
in the same conflict, inheritance, and final-method checks as explicitly
declared methods.
| Attribute | Target | Generated API |
|---|---|---|
| `#[Getter]` | Instance property, including a promoted property | `public function getName(): T` |
| `#[Setter]` | Mutable instance property, including a promoted property | `public function setName(T $name): void` |
| `#[With]` | Mutable instance property, including a promoted property | `public function withName(T $name): static`; clones the object, updates the clone, and returns it |
| `#[Constructor]` | Declared instance property | Adds the property to a generated public `__construct()` |
| `#[Printer]` | Named class | `public function __toString(): string` |
| `#[Arrayable]` | Named class | `public function toArray(): array` |
```php
<?php
#[Printer(fields: ['id', 'name'])]
#[Arrayable(fields: ['id', 'name'])]
final class User
{
#[Constructor, Getter, With]
public int $id;
#[Constructor, Getter, Setter]
public string $name = 'guest';
}
function main(): void
{
$user = new User(7);
$user->setName('Alice');
$copy = $user->withId(8);
echo $user->getId(); // 7
echo $copy->getId(); // 8
echo $user; // User(id=7, name=Alice)
echo $user->toArray()['name'];
}
```
Without `fields`, `#[Printer]` and `#[Arrayable]` use the class's own public
instance properties. The positional form, such as `#[Arrayable(['id'])]`, is
equivalent to `#[Arrayable(fields: ['id'])]`.
`#[Getter]`, `#[Setter]`, and `#[With]` cannot target static properties or
properties with hooks. `#[Setter]` and `#[With]` additionally reject readonly
properties. `#[Constructor]` cannot be used when the class already declares
`__construct()`, and required constructor properties must precede properties
with defaults. A generated method name that conflicts with a declared or
inherited final method is a compile-time error.
## Examples
### 1. Native types — compile-time numeric speedup
@ -326,7 +517,7 @@ Write performance-critical kernels in C++ and call them from PHP:
using namespace php;
var php_fast_sum(Int a, Int b) {
Int php_fast_sum(Int a, Int b) {
return a + b;
}
```
@ -334,7 +525,7 @@ var php_fast_sum(Int a, Int b) {
```php
<?php
// math.stub.php — declares the C++ function signature
function fast_sum(int $a, int $b): int;
function fast_sum(int $a, int $b): int {}
```
```php
@ -345,6 +536,10 @@ function main(): void
}
```
Add `math.cpp`, `math.stub.php`, and the calling PHP source to the same project
configuration. The `php_` C++ symbol prefix is the TypePHP callable ABI; stub
functions provide type metadata only and must not contain an implementation.
See [Mixed C++/PHP](docs/MIXED_CPP_PHP.md).
## Benchmark
@ -361,7 +556,13 @@ benchmarks that ship with the PHP source tree, compiled with `-O3`:
Both benchmarks measure core PHP language performance — function calls, object
property access, array/hash access, string handling, control flow, and more.
See the full per-item report in [`bench.txt`](bench.txt).
The checked-in workloads are [`examples/bench.php`](examples/bench.php) and
[`examples/micro_bench.php`](examples/micro_bench.php).
These numbers are a project measurement snapshot, not a performance guarantee.
PHP version, compiler, CPU, optimization flags, and enabled extensions can all
change the result; compare on the same machine with the same workload before
making deployment decisions.
### std::array vs PHP array
@ -375,7 +576,7 @@ A 10000×100000 element update loop, comparing PHP arrays against TypePHP's
| C++ `std::vector` | 6.2 s |
`std::array` is roughly **10× faster** than PHP arrays and performs
identically to hand-written C++. See the full benchmark in
close to the hand-written C++ result in this workload. See the benchmark in
[Std containers](docs/STD_CONTAINERS.md).
## Command Line
@ -419,13 +620,20 @@ Key options:
| `-m`, `--mode <bin\|lib\|ext>` | Build mode (default `bin`) |
| `-r`, `--run` | Run after a successful build |
| `-j`, `--job <num>` | Parallel compile jobs (default `4`) |
| `-f`, `--force` | Rebuild reusable PHPX objects instead of using the cache |
| `--build-dir <dir>` | Directory for generated C++ and intermediates |
| `--dry` | Generate C++ only, skip compile and link |
| `--php-version <8.4\|8.5>` | PHP syntax version to accept |
| `--cxx-std <ver>` | C++ standard (e.g. `c++17`, `c++20`) |
| `--march <arch>` | Target instruction set (e.g. `native`) |
| `--target-platform <triple>` | Cross-compilation target triple |
| `--lto` | Enable link-time optimization |
| `--sanitize <type>` | Enable a sanitizer (e.g. `address`) |
| `--profile` | Enable Linux gperftools profiling |
| `--format` | Format generated C++ with clang-format |
| `--no-literal-strings` | Disable the literal-string table optimization |
| `--no-progress`, `--no-color` | CI-friendly output controls |
| `-I`, `-D`, `-L`, `-l` | Repeatable native include, define, library path, and library options |
Run `bin/tpc.php --help` for the authoritative, up-to-date list. See
[Compiler CLI](docs/COMPILER_CLI.md) for details, including Bash completion:
@ -434,6 +642,24 @@ Run `bin/tpc.php --help` for the authoritative, up-to-date list. See
source <(./tpc --generate-completion=bash)
```
## Troubleshooting
- **`libphp.so` is missing:** install/build the matching PHP embed SAPI, set
`PHP_HOME`, or let `bin/tpc.php` offer the interactive Linux installer.
- **PHPX cannot be found:** set `PHPX_HOME` to a PHPX installation containing
`include/` and `lib/libphpx.so` (or the platform equivalent), then build PHPX
before compiling the project.
- **Startup crashes or ABI errors:** the PHP headers, `php-config`, `libphp`,
and loaded extension ABI must agree on the PHP version and ZTS/NTS mode. Do
not mix artifacts from different PHP builds.
- **Incremental builds are unexpectedly slow:** keep a stable `--build-dir` so
object and PCH caches can be reused. When an external test runner already
runs several tests concurrently, avoid multiplying that concurrency by an
unnecessarily large `tpc -j` value.
- **A project compiles with `bin/tpc.php` but fails with `tpc`:** reproduce with
the self-hosted compiler. Bootstrap execution can expose dynamic-call or ABI
paths that the PHP-hosted compiler does not exercise.
## Python bridge
TypePHP ships a Python tool submodule that shares the `tpc` entry point:
@ -449,6 +675,42 @@ TypePHP ships a Python tool submodule that shares the `tpc` entry point:
See [Python tool submodule](docs/python/tools.md).
## Development and testing
Install development dependencies and run the compiler unit suite:
```bash
composer install
PHPX_HOME=/path/to/phpx vendor/bin/phpunit
```
PHPT is the end-to-end suite. Build the self-hosted compiler first and pass it
explicitly to the test runner; using the Zend PHP executable as `--compiler`
does not test the deployed compiler:
```bash
PHPX_HOME=/path/to/phpx php bin/tpc.php project.yml --job 2 --no-progress
php run-tests.php -q -j8 --compiler ./tpc tests/compiler
```
Static analysis and the source-derived coverage matrix are separate checks:
```bash
composer analyse
php bin/analyze-test-coverage.php
php bin/analyze-test-coverage.php \
--format=markdown --output=build/test-coverage.md --strict
```
The coverage tool reports PHP version × feature × positive compilation ×
runtime semantics × negative diagnostics, plus concrete PHP-parser AST nodes.
It intentionally does not publish a single percentage without an explicit
denominator. See [Test coverage analyzer](docs/TEST_COVERAGE_ANALYZER.md).
GitHub Actions runs PHPUnit and self-hosted PHPT on PHP 8.4 and 8.5. Changes to
compiler behavior should add a focused PHPUnit test for internal/code-generation
rules and a PHPT whenever runtime output or diagnostics are observable.
## Documentation
- [Quick Start](docs/QUICKSTART.md) — minimal compilation flow
@ -458,10 +720,15 @@ See [Python tool submodule](docs/python/tools.md).
- [Native types](docs/NATIVE_TYPES.md) — native scalar types
- [High-precision types](docs/HIGH_PRECISION_TYPES.md) — BigInt / Decimal / BigFloat
- [Std containers](docs/STD_CONTAINERS.md) — strongly-typed containers
- [Universal methods](docs/UNIVERSAL_METHODS.md) — zero-overhead methods
- [Universal methods](docs/UNIVERSAL_METHODS.md) — compile-time method resolution
- [Compile-time functions](docs/COMPILE_TIME_FUNCTIONS.md) — `any()`, `refval()`, `objval()`, …
- [Mixed C++/PHP](docs/MIXED_CPP_PHP.md) — C++/PHP interop
- [`#[Immutable]`](docs/IMMUTABLE.md) — compile-time read-only contracts
- [`#[ArrayDef]`](docs/ARRAY_DEF.md) — typed array-property contracts
- [Property hooks](docs/PROPERTY_HOOKS.md) — PHP 8.4 hook lowering and runtime metadata
- [Object storage models](docs/OBJECT_STORAGE_AND_PASSING_MODELS.md) — Zend object, Box, and Native class boundaries
- [Generators](docs/YIELD_GENERATOR.md) — generator lowering and lifecycle
- [Test coverage analyzer](docs/TEST_COVERAGE_ANALYZER.md) — AST and feature evidence matrix
- [WASI build](docs/WASI_BUILD.md) — WASI targets
## License

Loading…
Cancel
Save