# TinyPHP **Repository Path**: kllxs_admin/TinyPHP ## Basic Information - **Project Name**: TinyPHP - **Description**: 一个零依赖的 PHP AOT 编译器 。 - **Primary Language**: PHP - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 0 - **Created**: 2025-08-08 - **Last Updated**: 2026-06-30 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README

TinyPHP logo

# TinyPHP > **PHP → C AOT 编译器** — 用 PHP 语法写原生二进制,零运行时依赖,性能飙 300-500 倍。 TinyPHP **不是** PHP 解释器或运行时替代品。它把 PHP 代码(强类型子集)编译成安全的 C,再由 GCC/Clang/TCC 编译为原生可执行文件。没有 Zend VM、没有 OPCache、不需要 PHP 环境。 ## 快速开始 ```bash # 编译单文件 php tphp.php test/var/var.php # 编译多文件(入口必须有全局 class Main) php tphp.php main.php demo.php # 带 C 源文件 php tphp.php main.php bridge.php lib.c # 扫描当前目录所有 .php / .c php tphp.php . # 指定输出 / 编译器 php tphp.php main.php -o app -cc gcc # 跨平台编译 php tphp.php main.php -os linux # x86_64 Linux php tphp.php main.php -os linux -arch aarch64 # ARM64 Linux php tphp.php main.php -os windows # Windows .exe ``` ### CLI 选项 | 选项 | 说明 | |---|---| | `-o ` | 输出文件路径 | | `-cc ` | 指定 C 编译器(默认内置 TCC) | | `-os ` | 跨编译目标:`windows`、`linux`、`macos` | | `-arch ` | 目标架构:`x86_64`、`aarch64`(Windows/Linux 默认 x86_64,macOS 默认 aarch64) | | `--debug` | 打印编译命令,运行二进制并与 `#debug` 预期输出逐行比对 | | `-h, --help` | 显示帮助 | ### 测试与调试(`#debug`) 在源码任意位置插入 `#debug` 指令声明预期输出,配合 `--debug` 自动编译运行并比对: ```php ` 空安全 | | 闭包 | `function() use($x) {}`、`fn($x) => expr`、多捕获、嵌套闭包 | | 异常 | `try/catch(Exception $e)/finally`、`throw new Exception()`、`never` 返回类型 | | 类型 | `int` `float` `string` `bool` `array` `callable` `void` `mixed` `self` 类类型 | | 运算符 | 完整 15 级优先级:算术/比较/逻辑/位/三元 `?:`/空合并 `??`/太空船 `<=>`/自增自减/类型转换 | | 命名空间 | `namespace A\B`、`use A\{B,C}` 分组导入、`use function` | | 语法糖 | `list()/$a[] =` 解构、`$a[] = ` push、`int &$x` 引用传参(全类型)、字符串插值、heredoc、魔术常量 (`__LINE__` `__FILE__` `__DIR__`) | ### ❌ 不支持(AOT 物理不可行) | 特性 | 原因 | 替代方案 | |------|------|---------| | `eval()` | 没有运行时解释器 | `switch`/`match` 分支调度,或回调分发 | | `$$var` 可变变量 | 编译时不知道变量名 | `array` 映射:`$map[$key]` 替代 `$$key` | | `include/require` | 没有运行时文件加载 | `#include` 引入 C 头文件,或多文件编译 | | `__call` `__get` `__set` | 没有运行时分发 | 显式定义方法,或用 `switch` 在单个方法内分发 | | `$obj->{$method}()` | 编译时不知道方法名 | 回调 map:`$fn = $map[$name]; $fn($args);` | | `yield` / Generator | 需要协程运行时(不做) | `array` 收集结果后返回,或回调遍历 | ### ⬜ 不做(权衡决定) | 特性 | 原因 | 替代方案 | |------|------|---------| | `?int` 可空类型 | AOT 下 null 分支需要运行时分发 | 用 `mixed` 替代,或拆分为两个重载函数 | | `...$args` 可变参数 | 需要动态栈构造 | 传 `array` 替代 | > `int|string` 联合类型和 `mixed` 已支持。 ### 🔢 内置函数 已实现 **193 个**(约 PHP 标准库的 70%),覆盖数组/字符串/数学/时间/JSON/哈希/进程控制/CSPRNG/ctype 等。详见 [FUNCTIONS.md](FUNCTIONS.md)。 ## 独有特性 ### AOT 类型固定 变量类型在首次赋值时确定,之后不可变。`===` 和 `==` 等价——编译期已知类型,**零运行时类型检查**。 ### COS 风格对象系统 对象头仅 16 字节(比 PHP 的 ~80B 精简 5 倍),struct 嵌套继承无开销,VTable 直接函数指针调用。作用域结束时自动调用 `__destruct` + 释放。 ### 多层内存优化 | 层 | 机制 | 效果 | |----|------|------| | SSO 小字符串 | 24B 内联缓冲区 | ≤23 字节零堆分配 | | 128KB 字符串池 | bump allocator + Arena 溢出块 | O(1) 分配,批量释放 | | 128 槽数组复用池 | LIFO + 1.5× 增长 | 热路径零 malloc | | 128 槽对象复用池 | LIFO | new+unset 提速 36-52% | | ROPE 多片段拼接 | 编译期展平为单次分配 | concat-4 提速 6 倍 | ### 三编译器 + 四平台 | | TCC | GCC | Clang | |---|---|---|---| | **Windows x86_64** | ✅ 默认内置 | ✅ | ✅ | | **Linux x86_64** | ✅ | ✅ | ✅ | | **Linux aarch64** | ✅ | ✅ | ✅ | | **macOS aarch64** | ✅ | ✅ | ✅ | TCC 亚秒编译,GCC/Clang -O2 带来 3-10 倍额外提速。`compat.h` 统一处理三编译器差异。 ### C 互操作(PHPC) 完整的 PHP ↔ C 双向互操作:`C->function(args)` 直接调用 C 函数,`c_int/c_str` 类型桥接,数组/对象/回调互操作。详见下方 PHPC 章节。 ### 扩展系统 对标 PHP extension,`#import` 按需引入。已内置 `pcntl`、`posix` 扩展: ```php 完整实现:`include/phpc.h`(~180 行),通过 `#include`/`#flag`/`C->call`/`c_*`/`php_*`/`phpc_*` 实现 PHP ↔ C 双向互操作。所有 phpc 函数为**全局函数**,不受命名空间 mangle。测试:`test/phpc/`。 ### 编译控制 ```php #include "include/demo.h" // 项目头文件 → #include "include/demo.h" #include Linux "linux_only.h" // 仅 Linux 引入 #include Windows // 仅 Windows 引入 #include __DIR__ . "/../demo.h" // 相对源文件目录向上 #include __EXT__ . "/demo/src/demo.h" // ext/ 目录引用 #include __INC__ . "/common.h" // include/ 目录引用 #include __CMD__ . "/local_lib.h" // 当前工作目录引用 #include __DIR__ . DIRECTORY_SEPARATOR . "x.h" // 跨平台路径分隔 #include // 系统头文件 → #include #flag Linux -lm // Linux 链接数学库 #flag GCC -O2 -DNDEBUG // 仅 GCC 优化 #flag Clang -Wall -Werror // 仅 Clang 严格警告 ``` `#include` 路径中支持 PHP 魔术常量展开: | 常量 | 展开为 | 示例 | |------|--------|------| | `__DIR__` | 源文件所在目录(绝对路径) | `__DIR__ . "/../demo.h"` | | `__EXT__` | 编译器 `ext/` 目录 | `__EXT__ . "/pcntl/src/pcntl.h"` | | `__INC__` | 编译器 `include/` 目录 | `__INC__ . "/common.h"` | | `__CMD__` | 执行 `tphp` 的当前工作目录 | `__CMD__ . "/my_lib.h"`(`tphp .` 时有用) | | `DIRECTORY_SEPARATOR` | `/`(Linux/macOS)或 `\`(Windows) | 跨平台路径拼接 | > 展开后经 `realpath()` 解析并校验在项目根目录内。`#include "path"` 和 `#include ` 的引号/尖括号格式不受影响,原样通过。 | 指令 | 语法 | 编译器输出 | 去重 | |------|------|-----------|------| | `#include [OS] "path"` | 项目相对路径,可选 OS 过滤 | `#include "path"` | 按文件名去重 | | `#include [OS] ` | 系统头文件,可选 OS 过滤 | `#include ` | 同上 | | `#flag [CC] [OS] flags` | 编译器+平台过滤 | 仅匹配时追加到命令行 | 按标志串去重 | > `[OS]` 可选:`Windows`/`Linux`/`MacOS`。不写 = 全平台。`#include` 和 `#flag` 共用同一过滤规则,`MacOS` 映射到 `Darwin`。 #### `#flag` / `#include` / `#import` 安全模型 为防止注入攻击,所有预处理指令受以下安全约束: | 指令 | 机制 | 说明 | |------|------|------| | `#flag` | **Shell 元字符阻断** | `` ` `` `$` `\|` `;` `&` `>` `<` `\n` `\\` 直接报错 | | | **Flag 前缀白名单** | 仅 `-I` `-L` `-l` `-D` `-U` `-O` `-W` `-std` `-m` `-f` `-g` `-pthread` `-static` `-shared` `-B` | | | **路径规范化** | `-I`/`-L` 路径经 `realpath()` 消解 `../` | | `#include` | **realpath + 边界校验** | 路径经 `realpath()` 解析后验证在项目根目录内 | | `#import` | **扩展名白名单** | 正则 `\w[\w\-]*` 仅接受字母/数字/下划线/连字符 | | | **工作区边界校验** | `realpath()` 后验证路径在 `ext/` 目录内 | > 对标 Vlang 的 `@DIR` 变量,TinyPHP 的 `__DIR__` 魔术常量在编译时展开,可在 `#include` 中用于跨目录引用。 ### 基础类型桥接 ``` PHP → C: C → PHP: c_int($x) → int32_t php_int(v) → t_int c_float($x) → double php_float(v) → t_float c_str($s) → const char* php_str(s) → t_string (深拷贝) ``` 直接 C 调用:`C->function(args)` → 生成原生 `function(args)`,无 `tphp_fn_` 前缀。 ### 数组互操作 **严格 C 风格**:`phpc_arr_int($arr)` 要求所有元素为 `TYPE_INT`,否则 `error()` 退出。`phpc_arr_dbl` 接受 `int` 或 `float`。 ```php // 模式: 提取 → C 操作 → 释放 function sum_array(array $arr): int { $data = phpc_arr_int($arr); // → int32_t* (malloc) $result = C->sum_ints($data, c_int(count($arr))); // C 操作 phpc_free($data); // 释放! return php_int($result); } ``` | PHP → C | 要求 | 返回 | |----------|------|------| | `phpc_arr_int($arr)` | 全部 TYPE_INT | `int32_t*` (malloc) | | `phpc_arr_dbl($arr)` | TYPE_INT 或 TYPE_FLOAT | `double*` (malloc) | | `phpc_arr_str($arr)` | 全部 TYPE_STRING | `char**` (malloc,每个字符串独立分配) | | C → PHP | 说明 | |----------|------| | `phpc_new_arr_int(src, len)` | `int32_t[]` → `t_array*` | | `phpc_new_arr_dbl(src, len)` | `double[]` → `t_array*` | | `phpc_new_arr_str(src, len)` | `char*[]` → `t_array*` | | `phpc_new_arr()` | 空数组 | ### 对象互操作 TinyPHP 对象 = `t_object` 头部 + 字段,`phpc_obj` 提取底层 C 结构体指针: ```php class MyPoint { public float $x; public float $y; } function obj_read_x(MyPoint $p): float { $ptr = phpc_obj($p); // → void* (即 tphp_class_MyPoint*) return php_float(C->read_field($ptr, c_int(16))); // offsetof(x) } ``` | 函数 | 方向 | 说明 | |------|------|------| | `phpc_obj($obj)` | PHP→C | 提取底层 C 结构体指针(`void*`) | | `phpc_new_obj(ptr, vtable)` | C→PHP | 包裹 C 指针为 PHP 对象(vtable 管理析构) | ### 回调互操作 **有 env 回调** — `phpc_fn_i32` + `phpc_env`: ```php $square = function(int $x): int { return $x * $x; }; $result = C->apply_closure( phpc_fn_i32($square), // → int32_t(*)(int32_t, void*) phpc_env($square), // → void* (env) c_int(5) ); // C 侧: int64_t apply_closure(int32_t (*fn)(int32_t, void*), void* env, int32_t val) ``` | 函数 | 返回类型 | |------|---------| | `phpc_fn_i32($cb)` | `int32_t(*)(int32_t, void*)` | | `phpc_fn_i64($cb)` | `int64_t(*)(int64_t, void*)` | | `phpc_fn_f64($cb)` | `double(*)(double, void*)` | | `phpc_fn($cb)` / `phpc_env($cb)` | `void*`(通用) | **无 env 回调** — `#callback` + `phpc_thunk()`(thunk 嵌入 env,任意签名): ```php #callback double fold_cb(int32_t idx, double val) // 声明 C 回调签名 C->fold_dbl($data, $len, phpc_thunk('fold_cb', $fn)); // 按签名生成 thunk // thunk: static double _thunk_N(int32_t idx, double val) { ... env嵌入 ... } ``` | 函数 | 说明 | |------|------| | `phpc_new_fn(func)` → `t_callback` | C 函数指针 → t_callback | | `phpc_new_fn_env(func, env)` | 带环境版本 | ### 所有权与内存安全 所有 PHPC 函数按所有权分三类,**搞错会导致 double-free 或内存泄漏**。 #### PHP → C(调用方负责释放) | 函数 | 返回类型 | 所有权 | |------|---------|--------| | `c_int($x)` | `int32_t` | 值拷贝,无所有权 | | `c_float($x)` | `double` | 值拷贝,无所有权 | | `c_str($s)` | `const char*` | **借用指针** ❌ 不可 `free` | | `phpc_arr_int($arr)` | `int32_t*` | **malloc** ⚠ 必须 `phpc_free()` | | `phpc_arr_dbl($arr)` | `double*` | **malloc** ⚠ 必须 `phpc_free()` | | `phpc_arr_str($arr)` | `char**` | **malloc** ⚠ 必须 `phpc_free_str_arr()` | | `phpc_obj($obj)` | `void*` | **借用指针** ❌ 不可 `free` | | `phpc_fn($cb)` / `phpc_env($cb)` | `void*` | 借用,无所有权 | | `phpc_fn_i32/i64/f64($cb)` | 函数指针 | 借用,无所有权 | #### C → PHP(TinyPHP 自动管理) | 函数 | 返回类型 | 所有权 | |------|---------|--------| | `php_int(v)` | `t_int` | 值拷贝 | | `php_float(v)` | `t_float` | 值拷贝 | | `php_str(s)` | `t_string` | **深拷贝**,字符串池自动释放 | | `phpc_new_arr_*(src, n)` | `t_array*` | 引用计数,自动 GC | | `phpc_new_arr()` | `t_array*` | 引用计数,自动 GC | | `phpc_new_obj(ptr, cls)` | `void*` | TinyPHP 析构链管理 | | `phpc_new_fn(func)` | `t_callback` | 值拷贝 | | `phpc_new_fn_env(fn, env)` | `t_callback` | 值拷贝 | #### 释放函数 | 函数 | 说明 | |------|------| | `phpc_free(ptr)` | `free(ptr)`,NULL 安全 | | `phpc_free_str_arr(strs, len)` | 先 `free` 每个字符串,再 `free` 指针数组 | > ⚠ **记忆口诀**:`phpc_arr_*`(提取)→ malloc → **你必须 phpc_free**。`phpc_new_*`(创建)→ TinyPHP GC → **你别管**。`c_str` / `phpc_obj` → 借用 → **别 free**。 ## 性能 PHP 8.5.1 vs TinyPHP(GCC -O2),详见 [BENCHMARK_RESULTS.md](BENCHMARK_RESULTS.md): - **数组遍历/读取**: 18-36x PHP,方法调用近乎 0ns - **OOP 创建/写入**: SSO + 对象池使 new+unset 反超 2.1x,prop write 反超 2.6x - **字符串拼接**: ROPE 多片段展平,concat-4 快 6 倍 - **编译器差距**: GCC/Clang -O2 比 TCC 再快 3-10x,`tphp -cc gcc` 即可获得 已落地优化:SSO 小字符串、Arena Allocator、对象复用池、ROPE 拼接、implode O(N²)→O(N)、CodeGen 自动释放。 ## 编译流水线 ``` PHP → Lexer → Token[] → Parser → AST → CodeGenerator → .c → 编译器 → 二进制 include/ (C 运行时头文件) ``` - **Lexer**: 逐字符扫描,~75 种 Token,支持字符串插值/heredoc - **Parser**: 递归下降,运算符优先级完整 - **CodeGenerator**: 访问者模式,生成类型安全的 C 代码 - **C 运行时**: COS 风格对象系统(16B 头 + struct 嵌套继承),setjmp/longjmp 异常,ROPE 多片段字符串拼接,256 位 JSON 转义位图,128 槽数组/对象复用池,64KB 字符串池,`compat.h` TCC/GCC/Clang 三编译器兼容层 - **编译器**: 内置 TCC (mob 分支),支持 GCC/Clang ## 文档 | 文件 | 说明 | |---|---| | [FUNCTIONS.md](FUNCTIONS.md) | 每个函数的实现细节与 PHP 差异 | | [GRAMMAR.md](GRAMMAR.md) | 完整语法参考(基于 PHP 8.5 parser,标注支持程度) | | [BENCHMARK_RESULTS.md](BENCHMARK_RESULTS.md) | 性能基准数据 | | [CONTRIBUTING.md](CONTRIBUTING.md) | 架构、扩展指南、安全规范 | | [QUICK_START.md](QUICK_START.md) | 5 分钟快速上手:加函数、跑测试、提 PR | ### 运行基准 ```bash php bench/run_bench.php # 默认 TCC php bench/run_bench.php gcc # GCC -O2 php bench/run_bench.php clang # Clang -O2 php bench/run_bench.php gcc php # 同时对比原生 PHP ``` ## 许可证 MIT