parent
ac7813d7b2
commit
473bd284ab
54 changed files with 4767 additions and 16 deletions
@ -0,0 +1,179 @@ |
||||
{ |
||||
"language": "zh", |
||||
"sections": [ |
||||
{ |
||||
"name": "项目概览", |
||||
"topics": [ |
||||
{ |
||||
"title": "项目简介", |
||||
"level": 1, |
||||
"slug": "overview", |
||||
"group": null |
||||
}, |
||||
{ |
||||
"title": "编译流水线", |
||||
"level": 1, |
||||
"slug": "pipeline", |
||||
"group": null |
||||
}, |
||||
{ |
||||
"title": "编译模式", |
||||
"level": 1, |
||||
"slug": "compilation-modes", |
||||
"group": null |
||||
}, |
||||
{ |
||||
"title": "快速开始", |
||||
"level": 1, |
||||
"slug": "quickstart", |
||||
"group": null |
||||
} |
||||
], |
||||
"groups": [] |
||||
}, |
||||
{ |
||||
"name": "前端:解析与符号", |
||||
"topics": [ |
||||
{ |
||||
"title": "解析器与 AST", |
||||
"level": 1, |
||||
"slug": "parser", |
||||
"group": null |
||||
}, |
||||
{ |
||||
"title": "预处理与符号表", |
||||
"level": 1, |
||||
"slug": "preprocessor", |
||||
"group": null |
||||
}, |
||||
{ |
||||
"title": "AST 转换(Lowering)", |
||||
"level": 1, |
||||
"slug": "transform", |
||||
"group": null |
||||
} |
||||
], |
||||
"groups": [] |
||||
}, |
||||
{ |
||||
"name": "类型系统", |
||||
"topics": [ |
||||
{ |
||||
"title": "原生类型映射", |
||||
"level": 1, |
||||
"slug": "native-types", |
||||
"group": null |
||||
}, |
||||
{ |
||||
"title": "类型检查与兼容", |
||||
"level": 1, |
||||
"slug": "type-check", |
||||
"group": null |
||||
}, |
||||
{ |
||||
"title": "高精度数值类型", |
||||
"level": 1, |
||||
"slug": "high-precision-types", |
||||
"group": null |
||||
} |
||||
], |
||||
"groups": [] |
||||
}, |
||||
{ |
||||
"name": "代码生成", |
||||
"topics": [ |
||||
{ |
||||
"title": "生成器总览", |
||||
"level": 1, |
||||
"slug": "generator", |
||||
"group": null |
||||
}, |
||||
{ |
||||
"title": "函数与类生成", |
||||
"level": 1, |
||||
"slug": "gen-functions-classes", |
||||
"group": null |
||||
}, |
||||
{ |
||||
"title": "扩展模块生成", |
||||
"level": 1, |
||||
"slug": "gen-extension", |
||||
"group": null |
||||
} |
||||
], |
||||
"groups": [] |
||||
}, |
||||
{ |
||||
"name": "后端与构建", |
||||
"topics": [ |
||||
{ |
||||
"title": "编译器后端", |
||||
"level": 1, |
||||
"slug": "backend", |
||||
"group": null |
||||
}, |
||||
{ |
||||
"title": "构建流水线", |
||||
"level": 1, |
||||
"slug": "build-pipeline", |
||||
"group": null |
||||
}, |
||||
{ |
||||
"title": "增量编译缓存", |
||||
"level": 1, |
||||
"slug": "incremental-cache", |
||||
"group": null |
||||
}, |
||||
{ |
||||
"title": "跨平台支持", |
||||
"level": 1, |
||||
"slug": "platform", |
||||
"group": null |
||||
} |
||||
], |
||||
"groups": [] |
||||
}, |
||||
{ |
||||
"name": "优化与性能", |
||||
"topics": [ |
||||
{ |
||||
"title": "优化器", |
||||
"level": 1, |
||||
"slug": "optimizer", |
||||
"group": null |
||||
}, |
||||
{ |
||||
"title": "编译期属性", |
||||
"level": 1, |
||||
"slug": "compile-time-attributes", |
||||
"group": null |
||||
}, |
||||
{ |
||||
"title": "构建速度与性能", |
||||
"level": 1, |
||||
"slug": "build-speed", |
||||
"group": null |
||||
} |
||||
], |
||||
"groups": [] |
||||
}, |
||||
{ |
||||
"name": "运行时与边界", |
||||
"topics": [ |
||||
{ |
||||
"title": "PHPX 运行时集成", |
||||
"level": 1, |
||||
"slug": "runtime", |
||||
"group": null |
||||
}, |
||||
{ |
||||
"title": "不支持的 PHP 特性", |
||||
"level": 1, |
||||
"slug": "incompatible-features", |
||||
"group": null |
||||
} |
||||
], |
||||
"groups": [] |
||||
} |
||||
] |
||||
} |
||||
@ -0,0 +1,43 @@ |
||||
<section> |
||||
项目概览 |
||||
<topic level="1" slug="overview">项目简介</topic> |
||||
<topic level="1" slug="pipeline">编译流水线</topic> |
||||
<topic level="1" slug="compilation-modes">编译模式</topic> |
||||
<topic level="1" slug="quickstart">快速开始</topic> |
||||
</section> |
||||
<section> |
||||
前端:解析与符号 |
||||
<topic level="1" slug="parser">解析器与 AST</topic> |
||||
<topic level="1" slug="preprocessor">预处理与符号表</topic> |
||||
<topic level="1" slug="transform">AST 转换(Lowering)</topic> |
||||
</section> |
||||
<section> |
||||
类型系统 |
||||
<topic level="1" slug="native-types">原生类型映射</topic> |
||||
<topic level="1" slug="type-check">类型检查与兼容</topic> |
||||
<topic level="1" slug="high-precision-types">高精度数值类型</topic> |
||||
</section> |
||||
<section> |
||||
代码生成 |
||||
<topic level="1" slug="generator">生成器总览</topic> |
||||
<topic level="1" slug="gen-functions-classes">函数与类生成</topic> |
||||
<topic level="1" slug="gen-extension">扩展模块生成</topic> |
||||
</section> |
||||
<section> |
||||
后端与构建 |
||||
<topic level="1" slug="backend">编译器后端</topic> |
||||
<topic level="1" slug="build-pipeline">构建流水线</topic> |
||||
<topic level="1" slug="incremental-cache">增量编译缓存</topic> |
||||
<topic level="1" slug="platform">跨平台支持</topic> |
||||
</section> |
||||
<section> |
||||
优化与性能 |
||||
<topic level="1" slug="optimizer">优化器</topic> |
||||
<topic level="1" slug="compile-time-attributes">编译期属性</topic> |
||||
<topic level="1" slug="build-speed">构建速度与性能</topic> |
||||
</section> |
||||
<section> |
||||
运行时与边界 |
||||
<topic level="1" slug="runtime">PHPX 运行时集成</topic> |
||||
<topic level="1" slug="incompatible-features">不支持的 PHP 特性</topic> |
||||
</section> |
||||
@ -0,0 +1,19 @@ |
||||
<!doctype html><html lang="zh"><head><meta charset="utf-8"> |
||||
<title>Project Wiki</title><style> |
||||
:root{--bg:#0f1117;--fg:#e6e6e6;--muted:#9aa0aa;--accent:#6ea8fe;--card:#171a21;--border:#262b36;} |
||||
*{box-sizing:border-box} |
||||
body{margin:0;font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background:var(--bg);color:var(--fg)} |
||||
#app{display:flex;height:100vh} |
||||
#side{width:300px;flex:0 0 300px;background:var(--card);border-right:1px solid var(--border);overflow:auto;padding:16px} |
||||
#side h2{font-size:15px;color:#fff;margin:18px 0 8px;padding-bottom:6px;border-bottom:1px solid var(--border)} |
||||
#side a{display:block;padding:5px 8px;border-radius:6px;color:var(--fg);text-decoration:none;font-size:13px} |
||||
#side a:hover{background:#222633} |
||||
#side a.lvl2{margin-left:12px;font-size:12px;color:var(--muted)} |
||||
#main{flex:1;background:var(--bg)} |
||||
#main iframe{width:100%;height:100%;border:none} |
||||
.meta{color:var(--muted);font-size:11px;margin-top:20px;border-top:1px solid var(--border);padding-top:10px} |
||||
</style></head> |
||||
<body><div id="app"> |
||||
<nav id="side"><h2>项目概览</h2><a class="lvl1" href="pages/overview.html" target="view">项目简介</a><a class="lvl1" href="pages/pipeline.html" target="view">编译流水线</a><a class="lvl1" href="pages/compilation-modes.html" target="view">编译模式</a><a class="lvl1" href="pages/quickstart.html" target="view">快速开始</a><h2>前端:解析与符号</h2><a class="lvl1" href="pages/parser.html" target="view">解析器与 AST</a><a class="lvl1" href="pages/preprocessor.html" target="view">预处理与符号表</a><a class="lvl1" href="pages/transform.html" target="view">AST 转换(Lowering)</a><h2>类型系统</h2><a class="lvl1" href="pages/native-types.html" target="view">原生类型映射</a><a class="lvl1" href="pages/type-check.html" target="view">类型检查与兼容</a><a class="lvl1" href="pages/high-precision-types.html" target="view">高精度数值类型</a><h2>代码生成</h2><a class="lvl1" href="pages/generator.html" target="view">生成器总览</a><a class="lvl1" href="pages/gen-functions-classes.html" target="view">函数与类生成</a><a class="lvl1" href="pages/gen-extension.html" target="view">扩展模块生成</a><h2>后端与构建</h2><a class="lvl1" href="pages/backend.html" target="view">编译器后端</a><a class="lvl1" href="pages/build-pipeline.html" target="view">构建流水线</a><a class="lvl1" href="pages/incremental-cache.html" target="view">增量编译缓存</a><a class="lvl1" href="pages/platform.html" target="view">跨平台支持</a><h2>优化与性能</h2><a class="lvl1" href="pages/optimizer.html" target="view">优化器</a><a class="lvl1" href="pages/compile-time-attributes.html" target="view">编译期属性</a><a class="lvl1" href="pages/build-speed.html" target="view">构建速度与性能</a><h2>运行时与边界</h2><a class="lvl1" href="pages/runtime.html" target="view">PHPX 运行时集成</a><a class="lvl1" href="pages/incompatible-features.html" target="view">不支持的 PHP 特性</a><div class="meta">rendered by code-wiki · static HTML</div></nav> |
||||
<main id="main"><iframe name="view" src="pages/overview.html"></iframe></main> |
||||
</div></body></html> |
||||
@ -0,0 +1,26 @@ |
||||
<!doctype html><html lang="zh"><head><meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width,initial-scale=1"> |
||||
<title>Project Wiki</title> |
||||
<script src="../script/mermaid.min.js"></script> |
||||
<script>document.addEventListener('DOMContentLoaded',function(){if(window.mermaid)mermaid.initialize({startOnLoad:true});});</script> |
||||
<style> |
||||
:root{--bg:#0f1117;--fg:#e6e6e6;--muted:#9aa0aa;--accent:#6ea8fe;--card:#171a21;--border:#262b36;} |
||||
*{box-sizing:border-box} |
||||
body{margin:0;font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background:var(--bg);color:var(--fg);line-height:1.65} |
||||
.wrap{max-width:900px;margin:0 auto;padding:32px 24px 80px} |
||||
h1,h2,h3{color:#fff;line-height:1.3;margin-top:1.6em} |
||||
h1{border-bottom:1px solid var(--border);padding-bottom:.3em} |
||||
a{color:var(--accent);text-decoration:none} |
||||
a:hover{text-decoration:underline} |
||||
code{background:#0b0d12;padding:.15em .4em;border-radius:4px;font-size:.9em} |
||||
pre{background:#0b0d12;border:1px solid var(--border);border-radius:8px;padding:14px;overflow:auto} |
||||
pre code{background:none;padding:0} |
||||
table{border-collapse:collapse;width:100%;margin:1em 0} |
||||
th,td{border:1px solid var(--border);padding:8px 10px;text-align:left} |
||||
th{background:var(--card)} |
||||
blockquote{border-left:3px solid var(--accent);margin:1em 0;padding:.2em 1em;color:var(--muted);background:var(--card)} |
||||
hr{border:none;border-top:1px solid var(--border);margin:2em 0} |
||||
</style></head> |
||||
<body><div class="wrap"><h1>Project Wiki</h1> |
||||
<p>This wiki was generated by <strong>code-wiki</strong> from the repository at <code>D:\git\php\aot-compiler</code>.</p> |
||||
<p>Select a topic from the left navigation to read its documentation.</p></div></body></html> |
||||
@ -0,0 +1,39 @@ |
||||
<!doctype html><html lang="zh"><head><meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width,initial-scale=1"> |
||||
<title>编译器后端</title> |
||||
<script src="../script/mermaid.min.js"></script> |
||||
<script>document.addEventListener('DOMContentLoaded',function(){if(window.mermaid)mermaid.initialize({startOnLoad:true});});</script> |
||||
<style> |
||||
:root{--bg:#0f1117;--fg:#e6e6e6;--muted:#9aa0aa;--accent:#6ea8fe;--card:#171a21;--border:#262b36;} |
||||
*{box-sizing:border-box} |
||||
body{margin:0;font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background:var(--bg);color:var(--fg);line-height:1.65} |
||||
.wrap{max-width:900px;margin:0 auto;padding:32px 24px 80px} |
||||
h1,h2,h3{color:#fff;line-height:1.3;margin-top:1.6em} |
||||
h1{border-bottom:1px solid var(--border);padding-bottom:.3em} |
||||
a{color:var(--accent);text-decoration:none} |
||||
a:hover{text-decoration:underline} |
||||
code{background:#0b0d12;padding:.15em .4em;border-radius:4px;font-size:.9em} |
||||
pre{background:#0b0d12;border:1px solid var(--border);border-radius:8px;padding:14px;overflow:auto} |
||||
pre code{background:none;padding:0} |
||||
table{border-collapse:collapse;width:100%;margin:1em 0} |
||||
th,td{border:1px solid var(--border);padding:8px 10px;text-align:left} |
||||
th{background:var(--card)} |
||||
blockquote{border-left:3px solid var(--accent);margin:1em 0;padding:.2em 1em;color:var(--muted);background:var(--card)} |
||||
hr{border:none;border-top:1px solid var(--border);margin:2em 0} |
||||
</style></head> |
||||
<body><div class="wrap"><h1>编译器后端</h1> |
||||
<p>TypePHP 不直接调 <code>g++</code>/<code>cl</code>,而是抽象出 <strong>平台(Platform)+ 编译器后端(Backend)</strong> 两层,由工厂在启动时自动探测。这样同一份生成代码能在 GCC / Clang / MSVC 下编译。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L164-L190">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Backend">src/Backend/</a></p> |
||||
<h2>抽象结构</h2> |
||||
<table><thead><tr><th>类</th><th>角色</th></tr></thead><tbody><tr><td><code>PlatformFactory</code></td><td>按 OS 创建 <code>Windows</code> / <code>Linux</code> / <code>macOS</code> 平台对象</td></tr><tr><td><code>CompilerFactory</code></td><td><code>detectCompilerName()</code> / <code>createByName()</code> / <code>autoDetect()</code> 选择后端</td></tr><tr><td><code>CompilerBackend</code>(接口)</td><td>定义编译/链接命令抽象</td></tr><tr><td><code>GccLikeBackend</code></td><td>GCC / Clang 共用逻辑</td></tr><tr><td><code>Gcc</code> / <code>Clang</code></td><td>具体后端</td></tr><tr><td><code>Msvc</code></td><td>MSVC(Windows)后端</td></tr></tbody></table> |
||||
<p><code>detectPlatform()</code> 先建平台,再探测编译器名,最后 <code>CompilerFactory::createByName()</code> 生成后端;若失败则告警并回退到旧逻辑(<code>initializeNewArchitecture()</code>)。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L164-L190">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L538-L560">src/Translator.php</a></p> |
||||
<h2>命令生成</h2> |
||||
<p>后端只负责「给定源/目标/选项 → 返回命令字符串」。真实的进程执行在 <a href="pages/build-pipeline.html">构建流水线</a> 的 <code>NativeBuilder</code> 中。例如:</p> |
||||
<ul><li><code>compileCommand()</code> / <code>linkCommand()</code> 产出可复现的命令行;</li><li>命令行本身被写进<strong>缓存键</strong>,确保编译参数变化能触发重编译。</li></ul> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1408-L1417">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1644-L1647">src/Translator.php</a></p> |
||||
<h2>预编译头</h2> |
||||
<p>后端是否支持 PCH 由 <code>supportsPrecompiledHeaders()</code> 决定;支持的会在构建期预编译 <code>phpx.h</code> 等全局头,显著加速后续编译单元。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1449-L1487">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Build\PrecompiledHeaderManager.php">src/Build/PrecompiledHeaderManager.php</a></p> |
||||
<h2>相关阅读</h2> |
||||
<ul><li>命令如何被执行与排队 → <a href="pages/build-pipeline.html">构建流水线</a></li><li>缓存如何依赖编译命令 → <a href="pages/incremental-cache.html">增量编译缓存</a></li><li>平台差异(Windows SDK / PHP lib) → <a href="pages/platform.html">跨平台支持</a></li></ul></div></body></html> |
||||
@ -0,0 +1,45 @@ |
||||
<blog> |
||||
|
||||
# 编译器后端 |
||||
|
||||
TypePHP 不直接调 `g++`/`cl`,而是抽象出 **平台(Platform)+ 编译器后端(Backend)** 两层,由工厂在启动时自动探测。这样同一份生成代码能在 GCC / Clang / MSVC 下编译。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L164-L190) · [src/Backend/](src/Backend/) |
||||
|
||||
## 抽象结构 |
||||
|
||||
| 类 | 角色 | |
||||
|---|---| |
||||
| `PlatformFactory` | 按 OS 创建 `Windows` / `Linux` / `macOS` 平台对象 | |
||||
| `CompilerFactory` | `detectCompilerName()` / `createByName()` / `autoDetect()` 选择后端 | |
||||
| `CompilerBackend`(接口) | 定义编译/链接命令抽象 | |
||||
| `GccLikeBackend` | GCC / Clang 共用逻辑 | |
||||
| `Gcc` / `Clang` | 具体后端 | |
||||
| `Msvc` | MSVC(Windows)后端 | |
||||
|
||||
`detectPlatform()` 先建平台,再探测编译器名,最后 `CompilerFactory::createByName()` 生成后端;若失败则告警并回退到旧逻辑(`initializeNewArchitecture()`)。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L164-L190) · [src/Translator.php](src/Translator.php#L538-L560) |
||||
|
||||
## 命令生成 |
||||
|
||||
后端只负责「给定源/目标/选项 → 返回命令字符串」。真实的进程执行在 [构建流水线](build-pipeline) 的 `NativeBuilder` 中。例如: |
||||
|
||||
- `compileCommand()` / `linkCommand()` 产出可复现的命令行; |
||||
- 命令行本身被写进**缓存键**,确保编译参数变化能触发重编译。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L1408-L1417) · [src/Translator.php](src/Translator.php#L1644-L1647) |
||||
|
||||
## 预编译头 |
||||
|
||||
后端是否支持 PCH 由 `supportsPrecompiledHeaders()` 决定;支持的会在构建期预编译 `phpx.h` 等全局头,显著加速后续编译单元。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L1449-L1487) · [src/Build/PrecompiledHeaderManager.php](src/Build/PrecompiledHeaderManager.php) |
||||
|
||||
## 相关阅读 |
||||
|
||||
- 命令如何被执行与排队 → [构建流水线](build-pipeline) |
||||
- 缓存如何依赖编译命令 → [增量编译缓存](incremental-cache) |
||||
- 平台差异(Windows SDK / PHP lib) → [跨平台支持](platform) |
||||
|
||||
</blog> |
||||
@ -0,0 +1,47 @@ |
||||
<!doctype html><html lang="zh"><head><meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width,initial-scale=1"> |
||||
<title>构建流水线</title> |
||||
<script src="../script/mermaid.min.js"></script> |
||||
<script>document.addEventListener('DOMContentLoaded',function(){if(window.mermaid)mermaid.initialize({startOnLoad:true});});</script> |
||||
<style> |
||||
:root{--bg:#0f1117;--fg:#e6e6e6;--muted:#9aa0aa;--accent:#6ea8fe;--card:#171a21;--border:#262b36;} |
||||
*{box-sizing:border-box} |
||||
body{margin:0;font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background:var(--bg);color:var(--fg);line-height:1.65} |
||||
.wrap{max-width:900px;margin:0 auto;padding:32px 24px 80px} |
||||
h1,h2,h3{color:#fff;line-height:1.3;margin-top:1.6em} |
||||
h1{border-bottom:1px solid var(--border);padding-bottom:.3em} |
||||
a{color:var(--accent);text-decoration:none} |
||||
a:hover{text-decoration:underline} |
||||
code{background:#0b0d12;padding:.15em .4em;border-radius:4px;font-size:.9em} |
||||
pre{background:#0b0d12;border:1px solid var(--border);border-radius:8px;padding:14px;overflow:auto} |
||||
pre code{background:none;padding:0} |
||||
table{border-collapse:collapse;width:100%;margin:1em 0} |
||||
th,td{border:1px solid var(--border);padding:8px 10px;text-align:left} |
||||
th{background:var(--card)} |
||||
blockquote{border-left:3px solid var(--accent);margin:1em 0;padding:.2em 1em;color:var(--muted);background:var(--card)} |
||||
hr{border:none;border-top:1px solid var(--border);margin:2em 0} |
||||
</style></head> |
||||
<body><div class="wrap"><h1>构建流水线</h1> |
||||
<p><code>Translator::compile()</code> 把生成的 C++ 与 phpx 运行时源文件编译为对象文件,<code>build()</code> 再链接成最终产物。两者都委托给 <code>src/Build/NativeBuilder</code>,它负责真正派发编译/链接进程。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1419-L1447">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1649-L1680">src/Translator.php</a></p> |
||||
<h2>compile() 步骤</h2> |
||||
<pre class="mermaid">flowchart TD |
||||
A["compile(sourceFiles)"] --> B["追加 phpx misc 源\nfiber_generator / helper / main / cli_title"] |
||||
B --> C["preparePhpXPrecompiledHeader()"] |
||||
C --> D["compileResourceFile() (Windows)"] |
||||
D --> E{"支持 pcntl 且 -j>1?"} |
||||
E -- "否" --> F["compileSourceFile() 串行"] |
||||
E -- "是" --> G["compileWithPcntl() 并行"]</pre> |
||||
<p>phpx misc 源(<code>typephp_fiber_generator.cc</code>、<code>typephp_helper.cc</code>、<code>typephp_main.cc</code>、<code>php_cli_process_title.c</code>、<code>ps_title.c</code>)按模式追加:embed 加 <code>typephp_main.cc</code>,bin 加 cli 标题源。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1423-L1434">src/Translator.php</a></p> |
||||
<h2>并行编译</h2> |
||||
<p><code>compileWithPcntl()</code> 在 Unix/Linux/macOS 用 <code>pcntl_fork</code> 多进程编译,进度条实时刷新;无 <code>pcntl</code> 扩展时自动降级为串行。每个 <code>compileFile()</code> 调用前都会先查 <a href="pages/incremental-cache.html">增量缓存</a>,命中则跳过。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1584-L1637">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1349-L1392">src/Translator.php</a></p> |
||||
<h2>NativeBuilder 与命令选项</h2> |
||||
<table><thead><tr><th>组件</th><th>职责</th></tr></thead><tbody><tr><td><code>NativeBuilder</code></td><td>真正执行 <code>compile</code> / <code>link</code>,返回 <code>command</code>/<code>status</code>/<code>output</code></td></tr><tr><td><code>NativeCommandOptionsTrait</code></td><td>汇总编译/链接选项</td></tr><tr><td><code>CompileOptions</code> / <code>LinkOptions</code> / <code>CommandOptions</code></td><td>选项数据对象</td></tr><tr><td><code>FileScanner</code></td><td>识别原生源文件(C/C++/汇编/ObjC)</td></tr><tr><td><code>SourceCompileQueue</code> / <code>SourcePipelineTrait</code></td><td>编译队列与流水线调度</td></tr><tr><td><code>ResourceCompilationTrait</code></td><td>Windows <code>.rc</code> → <code>.res</code></td></tr></tbody></table> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Build\NativeBuilder.php">src/Build/NativeBuilder.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Build">src/Build/</a></p> |
||||
<h2>build() 链接</h2> |
||||
<p><code>build()</code> 调 <code>NativeBuilder::link()</code>,Windows 模式下把 <code>.res</code> 资源文件并入目标;链接失败或产物未生成则 <code>error()</code> 退出。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1649-L1680">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1653-L1659">src/Translator.php</a></p> |
||||
<h2>相关阅读</h2> |
||||
<ul><li>后端如何产出命令 → <a href="pages/backend.html">编译器后端</a></li><li>缓存如何避免重复编译 → <a href="pages/incremental-cache.html">增量编译缓存</a></li><li>平台相关的链接差异 → <a href="pages/platform.html">跨平台支持</a></li></ul></div></body></html> |
||||
@ -0,0 +1,56 @@ |
||||
<blog> |
||||
|
||||
# 构建流水线 |
||||
|
||||
`Translator::compile()` 把生成的 C++ 与 phpx 运行时源文件编译为对象文件,`build()` 再链接成最终产物。两者都委托给 `src/Build/NativeBuilder`,它负责真正派发编译/链接进程。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L1419-L1447) · [src/Translator.php](src/Translator.php#L1649-L1680) |
||||
|
||||
## compile() 步骤 |
||||
|
||||
```mermaid |
||||
flowchart TD |
||||
A["compile(sourceFiles)"] --> B["追加 phpx misc 源\nfiber_generator / helper / main / cli_title"] |
||||
B --> C["preparePhpXPrecompiledHeader()"] |
||||
C --> D["compileResourceFile() (Windows)"] |
||||
D --> E{"支持 pcntl 且 -j>1?"} |
||||
E -- "否" --> F["compileSourceFile() 串行"] |
||||
E -- "是" --> G["compileWithPcntl() 并行"] |
||||
``` |
||||
|
||||
phpx misc 源(`typephp_fiber_generator.cc`、`typephp_helper.cc`、`typephp_main.cc`、`php_cli_process_title.c`、`ps_title.c`)按模式追加:embed 加 `typephp_main.cc`,bin 加 cli 标题源。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L1423-L1434) |
||||
|
||||
## 并行编译 |
||||
|
||||
`compileWithPcntl()` 在 Unix/Linux/macOS 用 `pcntl_fork` 多进程编译,进度条实时刷新;无 `pcntl` 扩展时自动降级为串行。每个 `compileFile()` 调用前都会先查 [增量缓存](incremental-cache),命中则跳过。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L1584-L1637) · [src/Translator.php](src/Translator.php#L1349-L1392) |
||||
|
||||
## NativeBuilder 与命令选项 |
||||
|
||||
| 组件 | 职责 | |
||||
|---|---| |
||||
| `NativeBuilder` | 真正执行 `compile` / `link`,返回 `command`/`status`/`output` | |
||||
| `NativeCommandOptionsTrait` | 汇总编译/链接选项 | |
||||
| `CompileOptions` / `LinkOptions` / `CommandOptions` | 选项数据对象 | |
||||
| `FileScanner` | 识别原生源文件(C/C++/汇编/ObjC) | |
||||
| `SourceCompileQueue` / `SourcePipelineTrait` | 编译队列与流水线调度 | |
||||
| `ResourceCompilationTrait` | Windows `.rc` → `.res` | |
||||
|
||||
Sources: [src/Build/NativeBuilder.php](src/Build/NativeBuilder.php) · [src/Build/](src/Build/) |
||||
|
||||
## build() 链接 |
||||
|
||||
`build()` 调 `NativeBuilder::link()`,Windows 模式下把 `.res` 资源文件并入目标;链接失败或产物未生成则 `error()` 退出。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L1649-L1680) · [src/Translator.php](src/Translator.php#L1653-L1659) |
||||
|
||||
## 相关阅读 |
||||
|
||||
- 后端如何产出命令 → [编译器后端](backend) |
||||
- 缓存如何避免重复编译 → [增量编译缓存](incremental-cache) |
||||
- 平台相关的链接差异 → [跨平台支持](platform) |
||||
|
||||
</blog> |
||||
@ -0,0 +1,38 @@ |
||||
<!doctype html><html lang="zh"><head><meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width,initial-scale=1"> |
||||
<title>构建速度与性能</title> |
||||
<script src="../script/mermaid.min.js"></script> |
||||
<script>document.addEventListener('DOMContentLoaded',function(){if(window.mermaid)mermaid.initialize({startOnLoad:true});});</script> |
||||
<style> |
||||
:root{--bg:#0f1117;--fg:#e6e6e6;--muted:#9aa0aa;--accent:#6ea8fe;--card:#171a21;--border:#262b36;} |
||||
*{box-sizing:border-box} |
||||
body{margin:0;font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background:var(--bg);color:var(--fg);line-height:1.65} |
||||
.wrap{max-width:900px;margin:0 auto;padding:32px 24px 80px} |
||||
h1,h2,h3{color:#fff;line-height:1.3;margin-top:1.6em} |
||||
h1{border-bottom:1px solid var(--border);padding-bottom:.3em} |
||||
a{color:var(--accent);text-decoration:none} |
||||
a:hover{text-decoration:underline} |
||||
code{background:#0b0d12;padding:.15em .4em;border-radius:4px;font-size:.9em} |
||||
pre{background:#0b0d12;border:1px solid var(--border);border-radius:8px;padding:14px;overflow:auto} |
||||
pre code{background:none;padding:0} |
||||
table{border-collapse:collapse;width:100%;margin:1em 0} |
||||
th,td{border:1px solid var(--border);padding:8px 10px;text-align:left} |
||||
th{background:var(--card)} |
||||
blockquote{border-left:3px solid var(--accent);margin:1em 0;padding:.2em 1em;color:var(--muted);background:var(--card)} |
||||
hr{border:none;border-top:1px solid var(--border);margin:2em 0} |
||||
</style></head> |
||||
<body><div class="wrap"><h1>构建速度与性能</h1> |
||||
<p>TypePHP 的「编译速度」包含两个维度:<strong>编译期(PHP→C++→二进制)自身耗时</strong> 与 <strong>生成产物的运行性能</strong>。本章聚焦前者——哪些环节最慢,以及已落地的优化。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\docs\AOT_BUILD_SPEED_RESEARCH.md">docs/AOT_BUILD_SPEED_RESEARCH.md</a> · <a href="file:///D:\git\php\aot-compiler\docs\aot-optimization-priority.md">docs/aot-optimization-priority.md</a></p> |
||||
<h2>时间都花在哪</h2> |
||||
<p>编译期主要成本:</p> |
||||
<ol><li><strong>PHP 解析</strong>:每个文件被多次解析(预处理一次、转换一次)——这是主要冗余;</li><li><strong>C++ 翻译</strong>:<code>doConvert()</code> 遍历 AST 并发射 C++;</li><li><strong>C++ 编译</strong>:大量 <code>.cc</code> 单元编译,受 PCH 与并行度影响;</li><li><strong>链接</strong>:最终链接往往是大项目瓶颈之一。</li></ol> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\docs\AOT_BUILD_SPEED_RESEARCH.md">docs/AOT_BUILD_SPEED_RESEARCH.md</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L2455-L2459">src/Translator.php</a></p> |
||||
<h2>已落地的优化</h2> |
||||
<table><thead><tr><th>优化</th><th>说明</th><th>位置</th></tr></thead><tbody><tr><td><strong>S1 合并解析</strong></td><td>同一文件 AST 在进程内缓存复用(<code>parseCachedAst</code>),消除重复解析</td><td><code>src/Translator.php</code> <code>parseCachedAst()</code></td></tr><tr><td><strong>S2 增量对象缓存</strong></td><td>生成单元按「编译命令 + PHP ABI + 生成头内容指纹」缓存 <code>.o</code>,改动一处不必全量重编</td><td><a href="pages/incremental-cache.html">增量编译缓存</a></td></tr><tr><td><strong>PCH 预编译头</strong></td><td>预编译 <code>phpx.h</code> 等全局头,加速每个编译单元</td><td><code>src/Build/PrecompiledHeaderManager.php</code></td></tr><tr><td><strong>并行编译</strong></td><td><code>-j</code> 用 <code>pcntl</code> 多进程编译</td><td><code>src/Translator.php</code> <code>compileWithPcntl()</code></td></tr><tr><td><strong>misc 缓存</strong></td><td>phpx 运行时源按 ABI 指纹缓存</td><td><code>hasMiscObjectFileCache()</code></td></tr></tbody></table> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1116-L1160">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1449-L1487">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1584-L1637">src/Translator.php</a></p> |
||||
<h2>调试与剖析</h2> |
||||
<ul><li><code>--dry</code>:只生成 C++,跳过编译/链接,用于检查翻译与定位;</li><li><code>--profile</code>:启用 gperftools 剖析(仅 Linux),并在 <code>./tpc app.prof</code> 模式调 <code>pprof --web</code>;</li><li><code>--no-progress</code> / <code>-j</code>:控制进度展示与并行度。</li></ul> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\compiler.php#L48-L73">src/compiler.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L30-L36">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L251-L255">src/Translator.php</a></p> |
||||
<h2>相关阅读</h2> |
||||
<ul><li>缓存机制细节 → <a href="pages/incremental-cache.html">增量编译缓存</a></li><li>优化器如何提升产物性能 → <a href="pages/optimizer.html">优化器</a></li><li>优先级规划 → <code>docs/aot-optimization-priority.md</code></li></ul></div></body></html> |
||||
@ -0,0 +1,46 @@ |
||||
<blog> |
||||
|
||||
# 构建速度与性能 |
||||
|
||||
TypePHP 的「编译速度」包含两个维度:**编译期(PHP→C++→二进制)自身耗时** 与 **生成产物的运行性能**。本章聚焦前者——哪些环节最慢,以及已落地的优化。 |
||||
|
||||
Sources: [docs/AOT_BUILD_SPEED_RESEARCH.md](docs/AOT_BUILD_SPEED_RESEARCH.md) · [docs/aot-optimization-priority.md](docs/aot-optimization-priority.md) |
||||
|
||||
## 时间都花在哪 |
||||
|
||||
编译期主要成本: |
||||
|
||||
1. **PHP 解析**:每个文件被多次解析(预处理一次、转换一次)——这是主要冗余; |
||||
2. **C++ 翻译**:`doConvert()` 遍历 AST 并发射 C++; |
||||
3. **C++ 编译**:大量 `.cc` 单元编译,受 PCH 与并行度影响; |
||||
4. **链接**:最终链接往往是大项目瓶颈之一。 |
||||
|
||||
Sources: [docs/AOT_BUILD_SPEED_RESEARCH.md](docs/AOT_BUILD_SPEED_RESEARCH.md) · [src/Translator.php](src/Translator.php#L2455-L2459) |
||||
|
||||
## 已落地的优化 |
||||
|
||||
| 优化 | 说明 | 位置 | |
||||
|---|---|---| |
||||
| **S1 合并解析** | 同一文件 AST 在进程内缓存复用(`parseCachedAst`),消除重复解析 | `src/Translator.php` `parseCachedAst()` | |
||||
| **S2 增量对象缓存** | 生成单元按「编译命令 + PHP ABI + 生成头内容指纹」缓存 `.o`,改动一处不必全量重编 | [增量编译缓存](incremental-cache) | |
||||
| **PCH 预编译头** | 预编译 `phpx.h` 等全局头,加速每个编译单元 | `src/Build/PrecompiledHeaderManager.php` | |
||||
| **并行编译** | `-j` 用 `pcntl` 多进程编译 | `src/Translator.php` `compileWithPcntl()` | |
||||
| **misc 缓存** | phpx 运行时源按 ABI 指纹缓存 | `hasMiscObjectFileCache()` | |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L1116-L1160) · [src/Translator.php](src/Translator.php#L1449-L1487) · [src/Translator.php](src/Translator.php#L1584-L1637) |
||||
|
||||
## 调试与剖析 |
||||
|
||||
- `--dry`:只生成 C++,跳过编译/链接,用于检查翻译与定位; |
||||
- `--profile`:启用 gperftools 剖析(仅 Linux),并在 `./tpc app.prof` 模式调 `pprof --web`; |
||||
- `--no-progress` / `-j`:控制进度展示与并行度。 |
||||
|
||||
Sources: [src/compiler.php](src/compiler.php#L48-L73) · [src/Translator.php](src/Translator.php#L30-L36) · [src/Translator.php](src/Translator.php#L251-L255) |
||||
|
||||
## 相关阅读 |
||||
|
||||
- 缓存机制细节 → [增量编译缓存](incremental-cache) |
||||
- 优化器如何提升产物性能 → [优化器](optimizer) |
||||
- 优先级规划 → `docs/aot-optimization-priority.md` |
||||
|
||||
</blog> |
||||
@ -0,0 +1,46 @@ |
||||
<!doctype html><html lang="zh"><head><meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width,initial-scale=1"> |
||||
<title>编译模式</title> |
||||
<script src="../script/mermaid.min.js"></script> |
||||
<script>document.addEventListener('DOMContentLoaded',function(){if(window.mermaid)mermaid.initialize({startOnLoad:true});});</script> |
||||
<style> |
||||
:root{--bg:#0f1117;--fg:#e6e6e6;--muted:#9aa0aa;--accent:#6ea8fe;--card:#171a21;--border:#262b36;} |
||||
*{box-sizing:border-box} |
||||
body{margin:0;font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background:var(--bg);color:var(--fg);line-height:1.65} |
||||
.wrap{max-width:900px;margin:0 auto;padding:32px 24px 80px} |
||||
h1,h2,h3{color:#fff;line-height:1.3;margin-top:1.6em} |
||||
h1{border-bottom:1px solid var(--border);padding-bottom:.3em} |
||||
a{color:var(--accent);text-decoration:none} |
||||
a:hover{text-decoration:underline} |
||||
code{background:#0b0d12;padding:.15em .4em;border-radius:4px;font-size:.9em} |
||||
pre{background:#0b0d12;border:1px solid var(--border);border-radius:8px;padding:14px;overflow:auto} |
||||
pre code{background:none;padding:0} |
||||
table{border-collapse:collapse;width:100%;margin:1em 0} |
||||
th,td{border:1px solid var(--border);padding:8px 10px;text-align:left} |
||||
th{background:var(--card)} |
||||
blockquote{border-left:3px solid var(--accent);margin:1em 0;padding:.2em 1em;color:var(--muted);background:var(--card)} |
||||
hr{border:none;border-top:1px solid var(--border);margin:2em 0} |
||||
</style></head> |
||||
<body><div class="wrap"><h1>编译模式</h1> |
||||
<p>TypePHP 通过 <code>-m / --mode</code> 支持三种产物形态,由 <code>Translator::setBuildMode()</code> 归一化。三种模式共享同一套 PHP→C++ 翻译,区别只在于<strong>入口约定与链接目标</strong>。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L574-L589">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\docs\COMPILATION_MODES.md">docs/COMPILATION_MODES.md</a></p> |
||||
<h2>三种模式对比</h2> |
||||
<table><thead><tr><th>模式</th><th>参数</th><th>产物</th><th>入口要求</th><th>典型用途</th></tr></thead><tbody><tr><td>二进制</td><td><code>bin</code>(默认)</td><td>独立可执行文件</td><td>必须定义 <code>main()</code></td><td>CLI 工具、独立服务</td></tr><tr><td>共享库</td><td><code>lib</code></td><td><code>.so</code> / <code>.dll</code> / <code>.dylib</code></td><td>不需要 <code>main()</code></td><td>供其它程序调用的逻辑库</td></tr><tr><td>扩展</td><td><code>ext</code></td><td>PHP 扩展 <code>.so</code></td><td>不需要 <code>main()</code></td><td>嵌入现有 PHP 应用(php-fpm 等)</td></tr></tbody></table> |
||||
<p><code>bin</code> 是 <code>binary/cli</code> 的别名;<code>lib</code> 涵盖 <code>library/shared/dll/dylib/so</code>;<code>ext</code> 等价于 <code>extension</code>。未知值会报错退出。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L574-L589">src/Translator.php</a></p> |
||||
<h2>二进制模式(embed)</h2> |
||||
<p><code>bin</code> 模式在 <code>genExtension()</code> 中嵌入 <code>cli_set_process_title</code> / <code>cli_get_process_title</code> 内置函数,并在 <code>RINIT</code> 阶段用 <code>php::eval</code> 直接执行 <code>main()</code>(带 <code>$argc/$argv</code> 或空参数两种签名)。</p> |
||||
<pre class="mermaid">flowchart LR |
||||
A["main()"] --> B["RINIT: php_app_init()"] |
||||
B --> C["php::eval('main($argc,$argv)')"] |
||||
C --> D["RSHUTDOWN: php_app_clean()"]</pre> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1043-L1066">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1055-L1059">src/Translator.php</a></p> |
||||
<h2>共享库模式</h2> |
||||
<p>库模式下,编译器会:</p> |
||||
<ul><li>对 <code>exported</code> 函数加上 <code>TYPEPHP_<NAME>_API</code> 导出宏;</li><li>生成 <code><target>.stub.php</code> 导入桩,供其它 TypePHP 工程按库调用;</li><li>在 Linux 上自动给目标名加 <code>lib</code> 前缀。</li></ul> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L652-L666">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L633-L650">src/Translator.php#L1736-L1738) · [src/Translator.php</a></p> |
||||
<h2>扩展模式</h2> |
||||
<p><code>ext</code> 模式会跳过 <code>main()</code>,使用 <code>ZEND_GET_MODULE()</code> 注册 Zend 模块,并在 <code>RSHUTDOWN</code> 清空函数/类/属性表以支持重复加载。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1033-L1037">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1090-L1091">src/Translator.php</a></p> |
||||
<h2>相关阅读</h2> |
||||
<ul><li>命令行全量参数见 <a href="pages/compile-time-attributes.html">编译期属性</a> 与 <code>docs/COMPILER_CLI.md</code>。</li><li>产物如何被链接 → <a href="pages/build-pipeline.html">构建流水线</a>。</li></ul></div></body></html> |
||||
@ -0,0 +1,54 @@ |
||||
<blog> |
||||
|
||||
# 编译模式 |
||||
|
||||
TypePHP 通过 `-m / --mode` 支持三种产物形态,由 `Translator::setBuildMode()` 归一化。三种模式共享同一套 PHP→C++ 翻译,区别只在于**入口约定与链接目标**。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L574-L589) · [docs/COMPILATION_MODES.md](docs/COMPILATION_MODES.md) |
||||
|
||||
## 三种模式对比 |
||||
|
||||
| 模式 | 参数 | 产物 | 入口要求 | 典型用途 | |
||||
|---|---|---|---|---| |
||||
| 二进制 | `bin`(默认) | 独立可执行文件 | 必须定义 `main()` | CLI 工具、独立服务 | |
||||
| 共享库 | `lib` | `.so` / `.dll` / `.dylib` | 不需要 `main()` | 供其它程序调用的逻辑库 | |
||||
| 扩展 | `ext` | PHP 扩展 `.so` | 不需要 `main()` | 嵌入现有 PHP 应用(php-fpm 等) | |
||||
|
||||
`bin` 是 `binary/cli` 的别名;`lib` 涵盖 `library/shared/dll/dylib/so`;`ext` 等价于 `extension`。未知值会报错退出。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L574-L589) |
||||
|
||||
## 二进制模式(embed) |
||||
|
||||
`bin` 模式在 `genExtension()` 中嵌入 `cli_set_process_title` / `cli_get_process_title` 内置函数,并在 `RINIT` 阶段用 `php::eval` 直接执行 `main()`(带 `$argc/$argv` 或空参数两种签名)。 |
||||
|
||||
```mermaid |
||||
flowchart LR |
||||
A["main()"] --> B["RINIT: php_app_init()"] |
||||
B --> C["php::eval('main($argc,$argv)')"] |
||||
C --> D["RSHUTDOWN: php_app_clean()"] |
||||
``` |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L1043-L1066) · [src/Translator.php](src/Translator.php#L1055-L1059) |
||||
|
||||
## 共享库模式 |
||||
|
||||
库模式下,编译器会: |
||||
- 对 `exported` 函数加上 `TYPEPHP_<NAME>_API` 导出宏; |
||||
- 生成 `<target>.stub.php` 导入桩,供其它 TypePHP 工程按库调用; |
||||
- 在 Linux 上自动给目标名加 `lib` 前缀。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L652-L666) · [src/Translator.php#L1736-L1738) · [src/Translator.php](src/Translator.php#L633-L650) |
||||
|
||||
## 扩展模式 |
||||
|
||||
`ext` 模式会跳过 `main()`,使用 `ZEND_GET_MODULE()` 注册 Zend 模块,并在 `RSHUTDOWN` 清空函数/类/属性表以支持重复加载。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L1033-L1037) · [src/Translator.php](src/Translator.php#L1090-L1091) |
||||
|
||||
## 相关阅读 |
||||
|
||||
- 命令行全量参数见 [编译期属性](compile-time-attributes) 与 `docs/COMPILER_CLI.md`。 |
||||
- 产物如何被链接 → [构建流水线](build-pipeline)。 |
||||
|
||||
</blog> |
||||
@ -0,0 +1,37 @@ |
||||
<!doctype html><html lang="zh"><head><meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width,initial-scale=1"> |
||||
<title>编译期属性</title> |
||||
<script src="../script/mermaid.min.js"></script> |
||||
<script>document.addEventListener('DOMContentLoaded',function(){if(window.mermaid)mermaid.initialize({startOnLoad:true});});</script> |
||||
<style> |
||||
:root{--bg:#0f1117;--fg:#e6e6e6;--muted:#9aa0aa;--accent:#6ea8fe;--card:#171a21;--border:#262b36;} |
||||
*{box-sizing:border-box} |
||||
body{margin:0;font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background:var(--bg);color:var(--fg);line-height:1.65} |
||||
.wrap{max-width:900px;margin:0 auto;padding:32px 24px 80px} |
||||
h1,h2,h3{color:#fff;line-height:1.3;margin-top:1.6em} |
||||
h1{border-bottom:1px solid var(--border);padding-bottom:.3em} |
||||
a{color:var(--accent);text-decoration:none} |
||||
a:hover{text-decoration:underline} |
||||
code{background:#0b0d12;padding:.15em .4em;border-radius:4px;font-size:.9em} |
||||
pre{background:#0b0d12;border:1px solid var(--border);border-radius:8px;padding:14px;overflow:auto} |
||||
pre code{background:none;padding:0} |
||||
table{border-collapse:collapse;width:100%;margin:1em 0} |
||||
th,td{border:1px solid var(--border);padding:8px 10px;text-align:left} |
||||
th{background:var(--card)} |
||||
blockquote{border-left:3px solid var(--accent);margin:1em 0;padding:.2em 1em;color:var(--muted);background:var(--card)} |
||||
hr{border:none;border-top:1px solid var(--border);margin:2em 0} |
||||
</style></head> |
||||
<body><div class="wrap"><h1>编译期属性</h1> |
||||
<p>除了 PHP 8 的运行时 attribute,TypePHP 引入一组<strong>编译期函数与属性</strong>,用于在翻译阶段向编译器传递类型/语义提示。它们被 <code>Transform</code> 层的 Lowering 算子在遍历 AST 时识别与校验。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Transform\CompileTimeAttribute.php">src/Transform/CompileTimeAttribute.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Transform\CompileTimeAttributeRegistry.php">src/Transform/CompileTimeAttributeRegistry.php</a> · <a href="file:///D:\git\php\aot-compiler\docs\COMPILE_TIME_FUNCTIONS.md">docs/COMPILE_TIME_FUNCTIONS.md</a></p> |
||||
<h2>核心编译期函数</h2> |
||||
<table><thead><tr><th>函数</th><th>用途</th></tr></thead><tbody><tr><td><code>any($v)</code></td><td>显式标记变量为「任意 PHP 值」(通用 <code>php::Var</code>),绕过原生类型推断</td></tr><tr><td><code>refval($v, Type)</code></td><td>以指定类型解释变量(类型恢复/断言)</td></tr><tr><td><code>objval($v, 'ClassName')</code></td><td>从数组/返回值恢复对象的类信息(见 <a href="pages/native-types.html">native-types</a>)</td></tr><tr><td><code>expected()</code> / <code>unexpected()</code></td><td>编译期断言/分支提示</td></tr></tbody></table> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\docs\COMPILE_TIME_FUNCTIONS.md">docs/COMPILE_TIME_FUNCTIONS.md</a></p> |
||||
<h2>编译期属性</h2> |
||||
<p><code>CompileTimeAttribute::validateNode()</code> 在 <code>Visitor::enterNode</code> 中对每个节点校验编译期属性;<code>CompileTimeAttributeRegistry</code> 维护已知属性注册表。典型如 <code>MustUse</code>(要求函数/方法有返回值且调用方使用)、<code>Any</code>(类型放宽)等——<code>Preprocessor</code> 在 <code>parseFunctionDecl()</code> 中也会对 <code>MustUse</code> 强行校验返回类型。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Transform\Visitor.php#L30">src/Transform/Visitor.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Preprocessor.php#L537">src/Preprocessor.php</a></p> |
||||
<h2>与 Lowering 的配合</h2> |
||||
<p><code>FunctionAttributeLowering</code> / <code>ConstructorLowering</code> / <code>GetterLowering</code> / <code>PropertyMethodLowering</code> 把带编译期属性的节点降级为可翻译结构;<code>RuntimeAttributeFactoryLowering</code> 作为独立访客挂在遍历链上,处理运行时工厂属性。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Transform\Visitor.php#L30-L35">src/Transform/Visitor.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L2467">src/Translator.php</a></p> |
||||
<h2>相关阅读</h2> |
||||
<ul><li>遍历中如何调用这些算子 → <a href="pages/transform.html">AST 转换</a></li><li>类型如何因此被放宽/恢复 → <a href="pages/type-check.html">类型检查与兼容</a></li><li>SSA 优化如何消费类型信息 → <a href="pages/optimizer.html">优化器</a></li></ul></div></body></html> |
||||
@ -0,0 +1,38 @@ |
||||
<blog> |
||||
|
||||
# 编译期属性 |
||||
|
||||
除了 PHP 8 的运行时 attribute,TypePHP 引入一组**编译期函数与属性**,用于在翻译阶段向编译器传递类型/语义提示。它们被 `Transform` 层的 Lowering 算子在遍历 AST 时识别与校验。 |
||||
|
||||
Sources: [src/Transform/CompileTimeAttribute.php](src/Transform/CompileTimeAttribute.php) · [src/Transform/CompileTimeAttributeRegistry.php](src/Transform/CompileTimeAttributeRegistry.php) · [docs/COMPILE_TIME_FUNCTIONS.md](docs/COMPILE_TIME_FUNCTIONS.md) |
||||
|
||||
## 核心编译期函数 |
||||
|
||||
| 函数 | 用途 | |
||||
|---|---| |
||||
| `any($v)` | 显式标记变量为「任意 PHP 值」(通用 `php::Var`),绕过原生类型推断 | |
||||
| `refval($v, Type)` | 以指定类型解释变量(类型恢复/断言) | |
||||
| `objval($v, 'ClassName')` | 从数组/返回值恢复对象的类信息(见 [native-types](native-types)) | |
||||
| `expected()` / `unexpected()` | 编译期断言/分支提示 | |
||||
|
||||
Sources: [docs/COMPILE_TIME_FUNCTIONS.md](docs/COMPILE_TIME_FUNCTIONS.md) |
||||
|
||||
## 编译期属性 |
||||
|
||||
`CompileTimeAttribute::validateNode()` 在 `Visitor::enterNode` 中对每个节点校验编译期属性;`CompileTimeAttributeRegistry` 维护已知属性注册表。典型如 `MustUse`(要求函数/方法有返回值且调用方使用)、`Any`(类型放宽)等——`Preprocessor` 在 `parseFunctionDecl()` 中也会对 `MustUse` 强行校验返回类型。 |
||||
|
||||
Sources: [src/Transform/Visitor.php](src/Transform/Visitor.php#L30) · [src/Preprocessor.php](src/Preprocessor.php#L537) |
||||
|
||||
## 与 Lowering 的配合 |
||||
|
||||
`FunctionAttributeLowering` / `ConstructorLowering` / `GetterLowering` / `PropertyMethodLowering` 把带编译期属性的节点降级为可翻译结构;`RuntimeAttributeFactoryLowering` 作为独立访客挂在遍历链上,处理运行时工厂属性。 |
||||
|
||||
Sources: [src/Transform/Visitor.php](src/Transform/Visitor.php#L30-L35) · [src/Translator.php](src/Translator.php#L2467) |
||||
|
||||
## 相关阅读 |
||||
|
||||
- 遍历中如何调用这些算子 → [AST 转换](transform) |
||||
- 类型如何因此被放宽/恢复 → [类型检查与兼容](type-check) |
||||
- SSA 优化如何消费类型信息 → [优化器](optimizer) |
||||
|
||||
</blog> |
||||
@ -0,0 +1,44 @@ |
||||
<!doctype html><html lang="zh"><head><meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width,initial-scale=1"> |
||||
<title>扩展模块生成</title> |
||||
<script src="../script/mermaid.min.js"></script> |
||||
<script>document.addEventListener('DOMContentLoaded',function(){if(window.mermaid)mermaid.initialize({startOnLoad:true});});</script> |
||||
<style> |
||||
:root{--bg:#0f1117;--fg:#e6e6e6;--muted:#9aa0aa;--accent:#6ea8fe;--card:#171a21;--border:#262b36;} |
||||
*{box-sizing:border-box} |
||||
body{margin:0;font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background:var(--bg);color:var(--fg);line-height:1.65} |
||||
.wrap{max-width:900px;margin:0 auto;padding:32px 24px 80px} |
||||
h1,h2,h3{color:#fff;line-height:1.3;margin-top:1.6em} |
||||
h1{border-bottom:1px solid var(--border);padding-bottom:.3em} |
||||
a{color:var(--accent);text-decoration:none} |
||||
a:hover{text-decoration:underline} |
||||
code{background:#0b0d12;padding:.15em .4em;border-radius:4px;font-size:.9em} |
||||
pre{background:#0b0d12;border:1px solid var(--border);border-radius:8px;padding:14px;overflow:auto} |
||||
pre code{background:none;padding:0} |
||||
table{border-collapse:collapse;width:100%;margin:1em 0} |
||||
th,td{border:1px solid var(--border);padding:8px 10px;text-align:left} |
||||
th{background:var(--card)} |
||||
blockquote{border-left:3px solid var(--accent);margin:1em 0;padding:.2em 1em;color:var(--muted);background:var(--card)} |
||||
hr{border:none;border-top:1px solid var(--border);margin:2em 0} |
||||
</style></head> |
||||
<body><div class="wrap"><h1>扩展模块生成</h1> |
||||
<p><code>genExtension()</code> 是流水线里最大的一块生成逻辑,产出 <code>extension-<target>.cc</code>——一个标准 Zend 扩展模块。它把前面收集的所有类、函数、常量、全局变量缝合进 Zend 的生命周期钩子(MINIT / MINIT / RINIT / RSHUTDOWN)。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L739-L1105">src/Translator.php</a></p> |
||||
<h2>生成结构</h2> |
||||
<pre class="mermaid">flowchart TD |
||||
A["extension-<target>.cc"] --> B["全局变量 / 类表 / 函数表 / 属性表 声明"] |
||||
B --> C["php_get_class / php_get_func / php_get_method / php_get_prop"] |
||||
C --> D["ext_functions[] (ZEND_FE 列表)"] |
||||
D --> E["PHP_MINIT: 注册类/反射处理器/符号"] |
||||
E --> F["PHP_RINIT: php_app_init + eval(main)"] |
||||
F --> G["PHP_RSHUTDOWN: php_app_clean + request_shutdown"] |
||||
G --> H["zend_module_entry"]</pre> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L769-L1087">src/Translator.php</a></p> |
||||
<h2>关键片段</h2> |
||||
<ul><li><strong>符号解析函数</strong>:<code>php_get_class</code> / <code>php_get_func</code> / <code>php_get_method</code> / <code>php_get_prop</code> 用缓存的 <code>class_map</code> / <code>func_map</code> / <code>prop_map</code> 把字符串名映射到运行时 <code>zend_class_entry<em></code> / <code>zend_function</em></code>,带 <code>UNEXPECTED</code> 快路径。</li><li><strong>MINIT</strong>:安装 Fiber/Generator 类、反射属性处理器,逐个注册类并设置属性处理器;最后调用各 <code>registerSymbols</code> 函数。</li><li><strong>RINIT</strong>:<code>php_app_init()</code> 注册常量、全局变量、静态属性、类数组常量;<code>bin</code> 模式下 <code>php::eval</code> 执行 <code>main()</code>(按 <code>$argc/$argv</code> 或空参两种签名)。</li><li><strong>RSHUTDOWN</strong>:<code>php_app_clean()</code> 清理全局变量、VAR 常量、类数组常量(含继承来的数组常量),<code>ext</code> 模式额外清空三张映射表以支持模块重载。</li></ul> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L791-L837">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L884-L1066">src/Translator.php</a></p> |
||||
<h2>模式差异</h2> |
||||
<ul><li><code>bin</code>:嵌入 <code>cli_set_process_title</code>,<code>RINIT</code> 直接跑 <code>main()</code>;</li><li><code>lib</code>:Linux 下导出 <code>save_ps_args</code> 占位符;<code>getModuleName()</code> 仍生成模块入口;</li><li><code>ext</code>:用 <code>ZEND_GET_MODULE()</code>,跳过 <code>main()</code>,RSHUTDOWN 清空映射表。</li></ul> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L754-L767">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1090-L1096">src/Translator.php</a></p> |
||||
<h2>相关阅读</h2> |
||||
<ul><li>函数/类声明如何生成 → <a href="pages/gen-functions-classes.html">函数与类生成</a></li><li>生成的 <code>.cc</code> 如何被编译/缓存 → <a href="pages/incremental-cache.html">增量编译缓存</a></li><li>三种产物形态 → <a href="pages/compilation-modes.html">编译模式</a></li></ul></div></body></html> |
||||
@ -0,0 +1,47 @@ |
||||
<blog> |
||||
|
||||
# 扩展模块生成 |
||||
|
||||
`genExtension()` 是流水线里最大的一块生成逻辑,产出 `extension-<target>.cc`——一个标准 Zend 扩展模块。它把前面收集的所有类、函数、常量、全局变量缝合进 Zend 的生命周期钩子(MINIT / MINIT / RINIT / RSHUTDOWN)。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L739-L1105) |
||||
|
||||
## 生成结构 |
||||
|
||||
```mermaid |
||||
flowchart TD |
||||
A["extension-<target>.cc"] --> B["全局变量 / 类表 / 函数表 / 属性表 声明"] |
||||
B --> C["php_get_class / php_get_func / php_get_method / php_get_prop"] |
||||
C --> D["ext_functions[] (ZEND_FE 列表)"] |
||||
D --> E["PHP_MINIT: 注册类/反射处理器/符号"] |
||||
E --> F["PHP_RINIT: php_app_init + eval(main)"] |
||||
F --> G["PHP_RSHUTDOWN: php_app_clean + request_shutdown"] |
||||
G --> H["zend_module_entry"] |
||||
``` |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L769-L1087) |
||||
|
||||
## 关键片段 |
||||
|
||||
- **符号解析函数**:`php_get_class` / `php_get_func` / `php_get_method` / `php_get_prop` 用缓存的 `class_map` / `func_map` / `prop_map` 把字符串名映射到运行时 `zend_class_entry*` / `zend_function*`,带 `UNEXPECTED` 快路径。 |
||||
- **MINIT**:安装 Fiber/Generator 类、反射属性处理器,逐个注册类并设置属性处理器;最后调用各 `registerSymbols` 函数。 |
||||
- **RINIT**:`php_app_init()` 注册常量、全局变量、静态属性、类数组常量;`bin` 模式下 `php::eval` 执行 `main()`(按 `$argc/$argv` 或空参两种签名)。 |
||||
- **RSHUTDOWN**:`php_app_clean()` 清理全局变量、VAR 常量、类数组常量(含继承来的数组常量),`ext` 模式额外清空三张映射表以支持模块重载。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L791-L837) · [src/Translator.php](src/Translator.php#L884-L1066) |
||||
|
||||
## 模式差异 |
||||
|
||||
- `bin`:嵌入 `cli_set_process_title`,`RINIT` 直接跑 `main()`; |
||||
- `lib`:Linux 下导出 `save_ps_args` 占位符;`getModuleName()` 仍生成模块入口; |
||||
- `ext`:用 `ZEND_GET_MODULE()`,跳过 `main()`,RSHUTDOWN 清空映射表。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L754-L767) · [src/Translator.php](src/Translator.php#L1090-L1096) |
||||
|
||||
## 相关阅读 |
||||
|
||||
- 函数/类声明如何生成 → [函数与类生成](gen-functions-classes) |
||||
- 生成的 `.cc` 如何被编译/缓存 → [增量编译缓存](incremental-cache) |
||||
- 三种产物形态 → [编译模式](compilation-modes) |
||||
|
||||
</blog> |
||||
@ -0,0 +1,41 @@ |
||||
<!doctype html><html lang="zh"><head><meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width,initial-scale=1"> |
||||
<title>函数与类生成</title> |
||||
<script src="../script/mermaid.min.js"></script> |
||||
<script>document.addEventListener('DOMContentLoaded',function(){if(window.mermaid)mermaid.initialize({startOnLoad:true});});</script> |
||||
<style> |
||||
:root{--bg:#0f1117;--fg:#e6e6e6;--muted:#9aa0aa;--accent:#6ea8fe;--card:#171a21;--border:#262b36;} |
||||
*{box-sizing:border-box} |
||||
body{margin:0;font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background:var(--bg);color:var(--fg);line-height:1.65} |
||||
.wrap{max-width:900px;margin:0 auto;padding:32px 24px 80px} |
||||
h1,h2,h3{color:#fff;line-height:1.3;margin-top:1.6em} |
||||
h1{border-bottom:1px solid var(--border);padding-bottom:.3em} |
||||
a{color:var(--accent);text-decoration:none} |
||||
a:hover{text-decoration:underline} |
||||
code{background:#0b0d12;padding:.15em .4em;border-radius:4px;font-size:.9em} |
||||
pre{background:#0b0d12;border:1px solid var(--border);border-radius:8px;padding:14px;overflow:auto} |
||||
pre code{background:none;padding:0} |
||||
table{border-collapse:collapse;width:100%;margin:1em 0} |
||||
th,td{border:1px solid var(--border);padding:8px 10px;text-align:left} |
||||
th{background:var(--card)} |
||||
blockquote{border-left:3px solid var(--accent);margin:1em 0;padding:.2em 1em;color:var(--muted);background:var(--card)} |
||||
hr{border:none;border-top:1px solid var(--border);margin:2em 0} |
||||
</style></head> |
||||
<body><div class="wrap"><h1>函数与类生成</h1> |
||||
<p>本章聚焦两个最频繁的发射动作:<code>genFunctionWrapper()</code>(函数/方法 → C++ 函数)与 <code>genClassWrapper()</code>(类/接口/枚举 → C++ 类与 zend_class_entry 注册)。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L2515-L2528">src/Translator.php</a></p> |
||||
<h2>函数生成</h2> |
||||
<p><code>genFunctionDeclarations()</code> 为每个 <code>FunctionDef</code> 生成前向声明,规则包括:</p> |
||||
<ul><li><strong>方法</strong>:首参加 <code>php::Object &this_</code>;trait 父类场景追加 <code>zend_class_entry *trait_parent_ce</code>;</li><li><strong>变参</strong>:声明为 <code>php::Array</code> 并附默认参数表达式;</li><li><strong>多返回</strong>:在 <code>typephp_multi_return</code> 命名空间再生成一份返回元组版本(<code>hasMultiReturn()</code>);</li><li><strong>热/冷路径</strong>:<code>hot</code>/<code>cold</code> 加 <code>TYPEPHP_HOT_ATTRIBUTE</code> / <code>TYPEPHP_COLD_ATTRIBUTE</code>;</li><li><strong>导入/导出</strong>:跨库函数用 <code>TYPEPHP_<LIB>_IMPORT</code> 宏,库导出函数用 <code>TYPEPHP_<NAME>_API</code>。</li></ul> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1740-L1830">src/Translator.php</a></p> |
||||
<h2>类生成</h2> |
||||
<p><code>genClassWrapper()</code> 为每个 <code>ClassDef</code> / <code>InterfaceDef</code> 生成:</p> |
||||
<ol><li>C++ 类结构与属性布局;</li><li>静态属性默认值(<code>php::setStaticProperty</code>);</li><li><code>create_object</code> 钩子与属性处理器安装(<code>genClassPropertyInit()</code>);</li><li>数组常量(<code>genClassArrayConstants()</code>)。</li></ol> |
||||
<p>属性初始化分两种情况(<a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1909-L1963">src/Translator.php</a>):</p> |
||||
<ul><li><strong>标量/常量默认值</strong>:包成 <code>php::Var</code> 写入属性表;</li><li><strong>数组默认值</strong>:用 <code>ArrayInitPlan</code> 生成构造表达式,避免重复求值。</li></ul> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1894-L1966">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Preprocessor.php#L974-L1002">src/Preprocessor.php</a></p> |
||||
<h2>类注册排序</h2> |
||||
<p><code>genClassCeList()</code> 用 <code>marcj/topsort</code> 按继承依赖拓扑排序生成 <code>zend_class_entry</code> 注册顺序,确保父类先于子类注册;内置类/接口(不在符号表中)直接加入排序而不参与依赖解析。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L2539-L2568">src/Translator.php</a></p> |
||||
<h2>相关阅读</h2> |
||||
<ul><li>所有声明头如何汇总 → <a href="pages/generator.html">生成器总览</a></li><li>模块入口如何引用这些符号 → <a href="pages/gen-extension.html">扩展模块生成</a></li><li>属性类型约束 → <a href="pages/native-types.html">原生类型映射</a></li></ul></div></body></html> |
||||
@ -0,0 +1,48 @@ |
||||
<blog> |
||||
|
||||
# 函数与类生成 |
||||
|
||||
本章聚焦两个最频繁的发射动作:`genFunctionWrapper()`(函数/方法 → C++ 函数)与 `genClassWrapper()`(类/接口/枚举 → C++ 类与 zend_class_entry 注册)。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L2515-L2528) |
||||
|
||||
## 函数生成 |
||||
|
||||
`genFunctionDeclarations()` 为每个 `FunctionDef` 生成前向声明,规则包括: |
||||
|
||||
- **方法**:首参加 `php::Object &this_`;trait 父类场景追加 `zend_class_entry *trait_parent_ce`; |
||||
- **变参**:声明为 `php::Array` 并附默认参数表达式; |
||||
- **多返回**:在 `typephp_multi_return` 命名空间再生成一份返回元组版本(`hasMultiReturn()`); |
||||
- **热/冷路径**:`hot`/`cold` 加 `TYPEPHP_HOT_ATTRIBUTE` / `TYPEPHP_COLD_ATTRIBUTE`; |
||||
- **导入/导出**:跨库函数用 `TYPEPHP_<LIB>_IMPORT` 宏,库导出函数用 `TYPEPHP_<NAME>_API`。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L1740-L1830) |
||||
|
||||
## 类生成 |
||||
|
||||
`genClassWrapper()` 为每个 `ClassDef` / `InterfaceDef` 生成: |
||||
|
||||
1. C++ 类结构与属性布局; |
||||
2. 静态属性默认值(`php::setStaticProperty`); |
||||
3. `create_object` 钩子与属性处理器安装(`genClassPropertyInit()`); |
||||
4. 数组常量(`genClassArrayConstants()`)。 |
||||
|
||||
属性初始化分两种情况([src/Translator.php](src/Translator.php#L1909-L1963)): |
||||
- **标量/常量默认值**:包成 `php::Var` 写入属性表; |
||||
- **数组默认值**:用 `ArrayInitPlan` 生成构造表达式,避免重复求值。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L1894-L1966) · [src/Preprocessor.php](src/Preprocessor.php#L974-L1002) |
||||
|
||||
## 类注册排序 |
||||
|
||||
`genClassCeList()` 用 `marcj/topsort` 按继承依赖拓扑排序生成 `zend_class_entry` 注册顺序,确保父类先于子类注册;内置类/接口(不在符号表中)直接加入排序而不参与依赖解析。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L2539-L2568) |
||||
|
||||
## 相关阅读 |
||||
|
||||
- 所有声明头如何汇总 → [生成器总览](generator) |
||||
- 模块入口如何引用这些符号 → [扩展模块生成](gen-extension) |
||||
- 属性类型约束 → [原生类型映射](native-types) |
||||
|
||||
</blog> |
||||
@ -0,0 +1,37 @@ |
||||
<!doctype html><html lang="zh"><head><meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width,initial-scale=1"> |
||||
<title>生成器总览</title> |
||||
<script src="../script/mermaid.min.js"></script> |
||||
<script>document.addEventListener('DOMContentLoaded',function(){if(window.mermaid)mermaid.initialize({startOnLoad:true});});</script> |
||||
<style> |
||||
:root{--bg:#0f1117;--fg:#e6e6e6;--muted:#9aa0aa;--accent:#6ea8fe;--card:#171a21;--border:#262b36;} |
||||
*{box-sizing:border-box} |
||||
body{margin:0;font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background:var(--bg);color:var(--fg);line-height:1.65} |
||||
.wrap{max-width:900px;margin:0 auto;padding:32px 24px 80px} |
||||
h1,h2,h3{color:#fff;line-height:1.3;margin-top:1.6em} |
||||
h1{border-bottom:1px solid var(--border);padding-bottom:.3em} |
||||
a{color:var(--accent);text-decoration:none} |
||||
a:hover{text-decoration:underline} |
||||
code{background:#0b0d12;padding:.15em .4em;border-radius:4px;font-size:.9em} |
||||
pre{background:#0b0d12;border:1px solid var(--border);border-radius:8px;padding:14px;overflow:auto} |
||||
pre code{background:none;padding:0} |
||||
table{border-collapse:collapse;width:100%;margin:1em 0} |
||||
th,td{border:1px solid var(--border);padding:8px 10px;text-align:left} |
||||
th{background:var(--card)} |
||||
blockquote{border-left:3px solid var(--accent);margin:1em 0;padding:.2em 1em;color:var(--muted);background:var(--card)} |
||||
hr{border:none;border-top:1px solid var(--border);margin:2em 0} |
||||
</style></head> |
||||
<body><div class="wrap"><h1>生成器总览</h1> |
||||
<p>当 <code>doConvert()</code> 收集完一个文件的语句后,调用各 <code>genXxx</code> 方法把 PHP 构造发射为 C++。所有发射逻辑分两类:<strong>声明头文件生成</strong>(<code><em>.h</code>)与 <strong>实现单元生成</strong>(<code></em>.cc</code>)。<code>src/Generator/</code> 下是一组辅助生成器,负责闭包、匿名类、参数、资源文件等专项结构。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L2477-L2536">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Generator">src/Generator/</a></p> |
||||
<h2>主发射方法(在 Translator / CompilerBase)</h2> |
||||
<table><thead><tr><th>方法</th><th>产物</th></tr></thead><tbody><tr><td><code>genFunctionDeclarations()</code></td><td><code>php_<target>_func_decl.h</code>:所有函数前向声明</td></tr><tr><td><code>genDataDeclarations()</code></td><td><code>php_<target>_data_decl.h</code>:全局变量 / 常量 / 类映射表声明</td></tr><tr><td><code>genExtension()</code></td><td><code>extension-<target>.cc</code>:模块入口(MINIT/RINIT/RSHUTDOWN)</td></tr><tr><td><code>genClassWrapper()</code></td><td>单个类/接口的 C++ 实现</td></tr><tr><td><code>genFunctionWrapper()</code></td><td>单个函数的 C++ 实现</td></tr><tr><td><code>genClassPropertyInit()</code></td><td>属性默认值与 create_object 初始化块</td></tr></tbody></table> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1728-L1786">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L692-L737">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L739-L1105">src/Translator.php</a></p> |
||||
<h2>专项生成器(src/Generator/)</h2> |
||||
<table><thead><tr><th>生成器</th><th>负责</th></tr></thead><tbody><tr><td><code>ClosureGenerator</code></td><td>匿名函数 / 闭包 → C++ lambda 包装</td></tr><tr><td><code>AnonClassGenerator</code></td><td>匿名类</td></tr><tr><td><code>CallArgumentGenerator</code></td><td>调用实参的默认值/展开处理</td></tr><tr><td><code>DefaultArgumentGenerator</code></td><td>默认参数 helper(<code>genDefaultArgumentHelper*</code>)</td></tr><tr><td><code>FiberGenerator</code></td><td>协程 / Fiber 生成</td></tr><tr><td><code>PropertyPromotion</code></td><td>构造函数属性提升</td></tr><tr><td><code>ResourceFileGenerator</code></td><td>Windows <code>.rc</code> 资源文件</td></tr><tr><td><code>LibraryImportStubGenerator</code></td><td>跨库导入桩 <code><target>.stub.php</code></td></tr><tr><td><code>TypeCheckGenerator</code></td><td>运行时类型检查代码</td></tr><tr><td><code>Symbol</code></td><td>符号名转义工具</td></tr></tbody></table> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Generator">src/Generator/</a></p> |
||||
<h2>头文件依赖与增量缓存</h2> |
||||
<p>每个生成的 <code>.cc</code> 都 <code>#include</code> 项目级 <code>func_decl.h</code> / <code>data_decl.h</code> 与各自的 <code>_arginfo.h</code>。这些共享头文件的内容指纹正是 <a href="pages/incremental-cache.html">增量编译缓存</a> 判定是否重编译的依据——任一头变化都会让依赖它的 <code>.cc</code> 失效。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1253-L1270">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1880-L1892">src/Translator.php</a></p> |
||||
<h2>相关阅读</h2> |
||||
<ul><li>函数与类如何逐个生成 → <a href="pages/gen-functions-classes.html">函数与类生成</a></li><li>模块入口如何拼装 → <a href="pages/gen-extension.html">扩展模块生成</a></li><li>翻译前的 AST 改写 → <a href="pages/transform.html">AST 转换</a></li></ul></div></body></html> |
||||
@ -0,0 +1,51 @@ |
||||
<blog> |
||||
|
||||
# 生成器总览 |
||||
|
||||
当 `doConvert()` 收集完一个文件的语句后,调用各 `genXxx` 方法把 PHP 构造发射为 C++。所有发射逻辑分两类:**声明头文件生成**(`*.h`)与 **实现单元生成**(`*.cc`)。`src/Generator/` 下是一组辅助生成器,负责闭包、匿名类、参数、资源文件等专项结构。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L2477-L2536) · [src/Generator/](src/Generator/) |
||||
|
||||
## 主发射方法(在 Translator / CompilerBase) |
||||
|
||||
| 方法 | 产物 | |
||||
|---|---| |
||||
| `genFunctionDeclarations()` | `php_<target>_func_decl.h`:所有函数前向声明 | |
||||
| `genDataDeclarations()` | `php_<target>_data_decl.h`:全局变量 / 常量 / 类映射表声明 | |
||||
| `genExtension()` | `extension-<target>.cc`:模块入口(MINIT/RINIT/RSHUTDOWN) | |
||||
| `genClassWrapper()` | 单个类/接口的 C++ 实现 | |
||||
| `genFunctionWrapper()` | 单个函数的 C++ 实现 | |
||||
| `genClassPropertyInit()` | 属性默认值与 create_object 初始化块 | |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L1728-L1786) · [src/Translator.php](src/Translator.php#L692-L737) · [src/Translator.php](src/Translator.php#L739-L1105) |
||||
|
||||
## 专项生成器(src/Generator/) |
||||
|
||||
| 生成器 | 负责 | |
||||
|---|---| |
||||
| `ClosureGenerator` | 匿名函数 / 闭包 → C++ lambda 包装 | |
||||
| `AnonClassGenerator` | 匿名类 | |
||||
| `CallArgumentGenerator` | 调用实参的默认值/展开处理 | |
||||
| `DefaultArgumentGenerator` | 默认参数 helper(`genDefaultArgumentHelper*`) | |
||||
| `FiberGenerator` | 协程 / Fiber 生成 | |
||||
| `PropertyPromotion` | 构造函数属性提升 | |
||||
| `ResourceFileGenerator` | Windows `.rc` 资源文件 | |
||||
| `LibraryImportStubGenerator` | 跨库导入桩 `<target>.stub.php` | |
||||
| `TypeCheckGenerator` | 运行时类型检查代码 | |
||||
| `Symbol` | 符号名转义工具 | |
||||
|
||||
Sources: [src/Generator/](src/Generator/) |
||||
|
||||
## 头文件依赖与增量缓存 |
||||
|
||||
每个生成的 `.cc` 都 `#include` 项目级 `func_decl.h` / `data_decl.h` 与各自的 `_arginfo.h`。这些共享头文件的内容指纹正是 [增量编译缓存](incremental-cache) 判定是否重编译的依据——任一头变化都会让依赖它的 `.cc` 失效。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L1253-L1270) · [src/Translator.php](src/Translator.php#L1880-L1892) |
||||
|
||||
## 相关阅读 |
||||
|
||||
- 函数与类如何逐个生成 → [函数与类生成](gen-functions-classes) |
||||
- 模块入口如何拼装 → [扩展模块生成](gen-extension) |
||||
- 翻译前的 AST 改写 → [AST 转换](transform) |
||||
|
||||
</blog> |
||||
@ -0,0 +1,47 @@ |
||||
<!doctype html><html lang="zh"><head><meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width,initial-scale=1"> |
||||
<title>高精度数值类型</title> |
||||
<script src="../script/mermaid.min.js"></script> |
||||
<script>document.addEventListener('DOMContentLoaded',function(){if(window.mermaid)mermaid.initialize({startOnLoad:true});});</script> |
||||
<style> |
||||
:root{--bg:#0f1117;--fg:#e6e6e6;--muted:#9aa0aa;--accent:#6ea8fe;--card:#171a21;--border:#262b36;} |
||||
*{box-sizing:border-box} |
||||
body{margin:0;font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background:var(--bg);color:var(--fg);line-height:1.65} |
||||
.wrap{max-width:900px;margin:0 auto;padding:32px 24px 80px} |
||||
h1,h2,h3{color:#fff;line-height:1.3;margin-top:1.6em} |
||||
h1{border-bottom:1px solid var(--border);padding-bottom:.3em} |
||||
a{color:var(--accent);text-decoration:none} |
||||
a:hover{text-decoration:underline} |
||||
code{background:#0b0d12;padding:.15em .4em;border-radius:4px;font-size:.9em} |
||||
pre{background:#0b0d12;border:1px solid var(--border);border-radius:8px;padding:14px;overflow:auto} |
||||
pre code{background:none;padding:0} |
||||
table{border-collapse:collapse;width:100%;margin:1em 0} |
||||
th,td{border:1px solid var(--border);padding:8px 10px;text-align:left} |
||||
th{background:var(--card)} |
||||
blockquote{border-left:3px solid var(--accent);margin:1em 0;padding:.2em 1em;color:var(--muted);background:var(--card)} |
||||
hr{border:none;border-top:1px solid var(--border);margin:2em 0} |
||||
</style></head> |
||||
<body><div class="wrap"><h1>高精度数值类型</h1> |
||||
<p>PHP 原生 <code>int</code>(64 位)与 <code>float</code>(IEEE754 double)在金融、科学、密码学场景精度不足。TypePHP 提供三种高精度类型,底层直接调用成熟 C/C++ 数学库,<strong>零方法查找/解释器分派开销</strong>(运算本身仍有数学库计算与装箱成本)。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\docs\HIGH_PRECISION_TYPES.md#L1-L44">docs/HIGH_PRECISION_TYPES.md</a></p> |
||||
<h2>三种类型概览</h2> |
||||
<table><thead><tr><th>类型</th><th>底层库</th><th>特点</th></tr></thead><tbody><tr><td><code>bigInt</code> (<code>php::BigInt</code>)</td><td>GMP (<code>libgmp</code>)</td><td>任意精度整数,永不溢出</td></tr><tr><td><code>decimal</code> (<code>php::Decimal</code>)</td><td>libmpdec</td><td>十进制小数,约 50 位有效数字,无二进制浮点误差</td></tr><tr><td><code>bigFloat</code> (<code>php::BigFloat</code>)</td><td>MPFR (<code>libmpfr</code>)</td><td>默认 256 bit,字符串输出 64 位有效数字</td></tr></tbody></table> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\docs\HIGH_PRECISION_TYPES.md#L39-L43">docs/HIGH_PRECISION_TYPES.md</a> · <a href="file:///D:\git\php\aot-compiler\src\Type.php#L15-L17">src/Type.php</a></p> |
||||
<h2>使用前置</h2> |
||||
<pre><code><?php |
||||
declare(strict_types=1); |
||||
use native_types; |
||||
function main(): void { |
||||
$x = bigInt(123456789012345678901234567890); // 30 位整数不丢精度 |
||||
}</code></pre> |
||||
<p>系统需安装:<code>libgmp-dev</code>、<code>libmpdec-dev</code>、<code>libmpfr-dev</code>(见 README 依赖章节)。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\docs\HIGH_PRECISION_TYPES.md#L51-L59">docs/HIGH_PRECISION_TYPES.md</a> · <a href="file:///D:\git\php\aot-compiler\README.md#L29-L40">README.md</a></p> |
||||
<h2>能力</h2> |
||||
<ul><li><strong>算术/比较/复合赋值</strong>:<code>+ - * / %</code>、<code>< > ==</code> 以及 <code>+=</code> 等均可用于高精度类型;</li><li><strong>通用方法调用</strong>:通过 <a href="file:///D:\git\php\aot-compiler\universal-methods">通用方法</a>(见 <code>docs/UNIVERSAL_METHODS.md</code>)统一接口;</li><li><strong>类型转换</strong>:高精度类型之间及与原生类型可互转;</li><li><strong>超长字面量自动识别</strong>:超出原生范围的整数字面量自动识别为 <code>bigInt</code>;</li><li><strong>混合运算类型提升</strong>:不同精度参与运算时按规则提升。</li></ul> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\docs\HIGH_PRECISION_TYPES.md#L7-L17">docs/HIGH_PRECISION_TYPES.md</a></p> |
||||
<h2>设计取舍与优化</h2> |
||||
<p>相关设计文档(属于调研/规划,可能与当前实现有出入):</p> |
||||
<ul><li><code>docs/BIG_NUMBER_INPLACE_OPTIMIZATION_PLAN.md</code> —— 高精度类型原地运算优化方案;</li><li><code>docs/GMP_GAP.md</code> —— GMP 能力差异分析。</li></ul> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\docs\BIG_NUMBER_INPLACE_OPTIMIZATION_PLAN.md">docs/BIG_NUMBER_INPLACE_OPTIMIZATION_PLAN.md</a> · <a href="file:///D:\git\php\aot-compiler\docs\GMP_GAP.md">docs/GMP_GAP.md</a></p> |
||||
<h2>相关阅读</h2> |
||||
<ul><li>类型如何映射到 C++ → <a href="pages/native-types.html">原生类型映射</a></li><li>类型判定逻辑 → <a href="pages/type-check.html">类型检查与兼容</a></li><li>数组/容器配合 → <code>docs/STD_CONTAINERS.md</code></li></ul></div></body></html> |
||||
@ -0,0 +1,58 @@ |
||||
<blog> |
||||
|
||||
# 高精度数值类型 |
||||
|
||||
PHP 原生 `int`(64 位)与 `float`(IEEE754 double)在金融、科学、密码学场景精度不足。TypePHP 提供三种高精度类型,底层直接调用成熟 C/C++ 数学库,**零方法查找/解释器分派开销**(运算本身仍有数学库计算与装箱成本)。 |
||||
|
||||
Sources: [docs/HIGH_PRECISION_TYPES.md](docs/HIGH_PRECISION_TYPES.md#L1-L44) |
||||
|
||||
## 三种类型概览 |
||||
|
||||
| 类型 | 底层库 | 特点 | |
||||
|---|---|---| |
||||
| `bigInt` (`php::BigInt`) | GMP (`libgmp`) | 任意精度整数,永不溢出 | |
||||
| `decimal` (`php::Decimal`) | libmpdec | 十进制小数,约 50 位有效数字,无二进制浮点误差 | |
||||
| `bigFloat` (`php::BigFloat`) | MPFR (`libmpfr`) | 默认 256 bit,字符串输出 64 位有效数字 | |
||||
|
||||
Sources: [docs/HIGH_PRECISION_TYPES.md](docs/HIGH_PRECISION_TYPES.md#L39-L43) · [src/Type.php](src/Type.php#L15-L17) |
||||
|
||||
## 使用前置 |
||||
|
||||
```php |
||||
<?php |
||||
declare(strict_types=1); |
||||
use native_types; |
||||
function main(): void { |
||||
$x = bigInt(123456789012345678901234567890); // 30 位整数不丢精度 |
||||
} |
||||
``` |
||||
|
||||
系统需安装:`libgmp-dev`、`libmpdec-dev`、`libmpfr-dev`(见 README 依赖章节)。 |
||||
|
||||
Sources: [docs/HIGH_PRECISION_TYPES.md](docs/HIGH_PRECISION_TYPES.md#L51-L59) · [README.md](README.md#L29-L40) |
||||
|
||||
## 能力 |
||||
|
||||
- **算术/比较/复合赋值**:`+ - * / %`、`< > ==` 以及 `+=` 等均可用于高精度类型; |
||||
- **通用方法调用**:通过 [通用方法](universal-methods)(见 `docs/UNIVERSAL_METHODS.md`)统一接口; |
||||
- **类型转换**:高精度类型之间及与原生类型可互转; |
||||
- **超长字面量自动识别**:超出原生范围的整数字面量自动识别为 `bigInt`; |
||||
- **混合运算类型提升**:不同精度参与运算时按规则提升。 |
||||
|
||||
Sources: [docs/HIGH_PRECISION_TYPES.md](docs/HIGH_PRECISION_TYPES.md#L7-L17) |
||||
|
||||
## 设计取舍与优化 |
||||
|
||||
相关设计文档(属于调研/规划,可能与当前实现有出入): |
||||
- `docs/BIG_NUMBER_INPLACE_OPTIMIZATION_PLAN.md` —— 高精度类型原地运算优化方案; |
||||
- `docs/GMP_GAP.md` —— GMP 能力差异分析。 |
||||
|
||||
Sources: [docs/BIG_NUMBER_INPLACE_OPTIMIZATION_PLAN.md](docs/BIG_NUMBER_INPLACE_OPTIMIZATION_PLAN.md) · [docs/GMP_GAP.md](docs/GMP_GAP.md) |
||||
|
||||
## 相关阅读 |
||||
|
||||
- 类型如何映射到 C++ → [原生类型映射](native-types) |
||||
- 类型判定逻辑 → [类型检查与兼容](type-check) |
||||
- 数组/容器配合 → `docs/STD_CONTAINERS.md` |
||||
|
||||
</blog> |
||||
@ -0,0 +1,38 @@ |
||||
<!doctype html><html lang="zh"><head><meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width,initial-scale=1"> |
||||
<title>不支持的 PHP 特性</title> |
||||
<script src="../script/mermaid.min.js"></script> |
||||
<script>document.addEventListener('DOMContentLoaded',function(){if(window.mermaid)mermaid.initialize({startOnLoad:true});});</script> |
||||
<style> |
||||
:root{--bg:#0f1117;--fg:#e6e6e6;--muted:#9aa0aa;--accent:#6ea8fe;--card:#171a21;--border:#262b36;} |
||||
*{box-sizing:border-box} |
||||
body{margin:0;font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background:var(--bg);color:var(--fg);line-height:1.65} |
||||
.wrap{max-width:900px;margin:0 auto;padding:32px 24px 80px} |
||||
h1,h2,h3{color:#fff;line-height:1.3;margin-top:1.6em} |
||||
h1{border-bottom:1px solid var(--border);padding-bottom:.3em} |
||||
a{color:var(--accent);text-decoration:none} |
||||
a:hover{text-decoration:underline} |
||||
code{background:#0b0d12;padding:.15em .4em;border-radius:4px;font-size:.9em} |
||||
pre{background:#0b0d12;border:1px solid var(--border);border-radius:8px;padding:14px;overflow:auto} |
||||
pre code{background:none;padding:0} |
||||
table{border-collapse:collapse;width:100%;margin:1em 0} |
||||
th,td{border:1px solid var(--border);padding:8px 10px;text-align:left} |
||||
th{background:var(--card)} |
||||
blockquote{border-left:3px solid var(--accent);margin:1em 0;padding:.2em 1em;color:var(--muted);background:var(--card)} |
||||
hr{border:none;border-top:1px solid var(--border);margin:2em 0} |
||||
</style></head> |
||||
<body><div class="wrap"><h1>不支持的 PHP 特性</h1> |
||||
<p>AOT 编译对 PHP 运行时做了静态化假设,因此<strong>并非所有 PHP 特性都可编译</strong>。遇到编译报错(如 <code>Not implemented</code>)时,应据此清单判断是设计限制、有意规则,还是尚未实现。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\docs\INCOMPATIBLE_PHP_FEATURES.md">docs/INCOMPATIBLE_PHP_FEATURES.md</a> · <a href="file:///D:\git\php\aot-compiler\docs\PHP_INCOMPATIBILITY_CLASSIFICATION.md">docs/PHP_INCOMPATIBILITY_CLASSIFICATION.md</a></p> |
||||
<h2>不兼容分类</h2> |
||||
<p><code>PHP_INCOMPATIBILITY_CLASSIFICATION.md</code> 把限制分成四类,避免维护多份清单:</p> |
||||
<table><thead><tr><th>类别</th><th>含义</th></tr></thead><tbody><tr><td><strong>Hard Limit</strong></td><td>架构上无法支持(如依赖运行时动态加载的特性)</td></tr><tr><td><strong>Intentional Rule</strong></td><td>有意为之的设计规则(如可执行代码必须放进 <code>main()</code>)</td></tr><tr><td><strong>Pending</strong></td><td>计划支持但尚未实现</td></tr><tr><td><strong>Partial</strong></td><td>部分支持,有约束条件</td></tr></tbody></table> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\docs\PHP_INCOMPATIBILITY_CLASSIFICATION.md">docs/PHP_INCOMPATIBILITY_CLASSIFICATION.md</a></p> |
||||
<h2>常见设计规则</h2> |
||||
<ul><li><strong>游离可执行代码</strong>:文件顶层的可执行语句(循环、函数调用)不被允许,必须放在 <code>main()</code> 或函数体内;</li><li><strong>固定值类型属性不可 <code>unset</code>/赋 <code>null</code></strong>:见 <a href="pages/native-types.html">原生类型映射</a>;</li><li><strong>显式返回类型</strong>:函数/方法必须声明返回类型(<code>parseFunctionDecl()</code> 会 <code>fatalError</code>)。</li></ul> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\docs\QUICKSTART.md#L191-L203">docs/QUICKSTART.md</a> · <a href="file:///D:\git\php\aot-compiler\src\Preprocessor.php#L497-L536">src/Preprocessor.php</a></p> |
||||
<h2>维护约定</h2> |
||||
<ol><li>兼容性变化须<strong>同时更新</strong> <code>INCOMPATIBLE_PHP_FEATURES.md</code> 与分类文档;</li><li>所有语法/语义限制统一链接到当前兼容性清单,避免重复;</li><li>功能是否支持以 <strong>PHPT / PHPUnit 回归测试</strong> 为准;</li><li>历史研究文档(hhvm/kphp/peachpie 对比等)保留原始结论,不悄然改写为当前状态。</li></ol> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\docs\README.md#L30-L35">docs/README.md</a></p> |
||||
<h2>相关阅读</h2> |
||||
<ul><li>运行期能力边界 → <a href="pages/runtime.html">PHPX 运行时集成</a></li><li>类型约束 → <a href="pages/native-types.html">原生类型映射</a></li><li>属性/类约束 → <a href="pages/gen-functions-classes.html">函数与类生成</a></li></ul></div></body></html> |
||||
@ -0,0 +1,45 @@ |
||||
<blog> |
||||
|
||||
# 不支持的 PHP 特性 |
||||
|
||||
AOT 编译对 PHP 运行时做了静态化假设,因此**并非所有 PHP 特性都可编译**。遇到编译报错(如 `Not implemented`)时,应据此清单判断是设计限制、有意规则,还是尚未实现。 |
||||
|
||||
Sources: [docs/INCOMPATIBLE_PHP_FEATURES.md](docs/INCOMPATIBLE_PHP_FEATURES.md) · [docs/PHP_INCOMPATIBILITY_CLASSIFICATION.md](docs/PHP_INCOMPATIBILITY_CLASSIFICATION.md) |
||||
|
||||
## 不兼容分类 |
||||
|
||||
`PHP_INCOMPATIBILITY_CLASSIFICATION.md` 把限制分成四类,避免维护多份清单: |
||||
|
||||
| 类别 | 含义 | |
||||
|---|---| |
||||
| **Hard Limit** | 架构上无法支持(如依赖运行时动态加载的特性) | |
||||
| **Intentional Rule** | 有意为之的设计规则(如可执行代码必须放进 `main()`) | |
||||
| **Pending** | 计划支持但尚未实现 | |
||||
| **Partial** | 部分支持,有约束条件 | |
||||
|
||||
Sources: [docs/PHP_INCOMPATIBILITY_CLASSIFICATION.md](docs/PHP_INCOMPATIBILITY_CLASSIFICATION.md) |
||||
|
||||
## 常见设计规则 |
||||
|
||||
- **游离可执行代码**:文件顶层的可执行语句(循环、函数调用)不被允许,必须放在 `main()` 或函数体内; |
||||
- **固定值类型属性不可 `unset`/赋 `null`**:见 [原生类型映射](native-types); |
||||
- **显式返回类型**:函数/方法必须声明返回类型(`parseFunctionDecl()` 会 `fatalError`)。 |
||||
|
||||
Sources: [docs/QUICKSTART.md](docs/QUICKSTART.md#L191-L203) · [src/Preprocessor.php](src/Preprocessor.php#L497-L536) |
||||
|
||||
## 维护约定 |
||||
|
||||
1. 兼容性变化须**同时更新** `INCOMPATIBLE_PHP_FEATURES.md` 与分类文档; |
||||
2. 所有语法/语义限制统一链接到当前兼容性清单,避免重复; |
||||
3. 功能是否支持以 **PHPT / PHPUnit 回归测试** 为准; |
||||
4. 历史研究文档(hhvm/kphp/peachpie 对比等)保留原始结论,不悄然改写为当前状态。 |
||||
|
||||
Sources: [docs/README.md](docs/README.md#L30-L35) |
||||
|
||||
## 相关阅读 |
||||
|
||||
- 运行期能力边界 → [PHPX 运行时集成](runtime) |
||||
- 类型约束 → [原生类型映射](native-types) |
||||
- 属性/类约束 → [函数与类生成](gen-functions-classes) |
||||
|
||||
</blog> |
||||
@ -0,0 +1,42 @@ |
||||
<!doctype html><html lang="zh"><head><meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width,initial-scale=1"> |
||||
<title>增量编译缓存</title> |
||||
<script src="../script/mermaid.min.js"></script> |
||||
<script>document.addEventListener('DOMContentLoaded',function(){if(window.mermaid)mermaid.initialize({startOnLoad:true});});</script> |
||||
<style> |
||||
:root{--bg:#0f1117;--fg:#e6e6e6;--muted:#9aa0aa;--accent:#6ea8fe;--card:#171a21;--border:#262b36;} |
||||
*{box-sizing:border-box} |
||||
body{margin:0;font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background:var(--bg);color:var(--fg);line-height:1.65} |
||||
.wrap{max-width:900px;margin:0 auto;padding:32px 24px 80px} |
||||
h1,h2,h3{color:#fff;line-height:1.3;margin-top:1.6em} |
||||
h1{border-bottom:1px solid var(--border);padding-bottom:.3em} |
||||
a{color:var(--accent);text-decoration:none} |
||||
a:hover{text-decoration:underline} |
||||
code{background:#0b0d12;padding:.15em .4em;border-radius:4px;font-size:.9em} |
||||
pre{background:#0b0d12;border:1px solid var(--border);border-radius:8px;padding:14px;overflow:auto} |
||||
pre code{background:none;padding:0} |
||||
table{border-collapse:collapse;width:100%;margin:1em 0} |
||||
th,td{border:1px solid var(--border);padding:8px 10px;text-align:left} |
||||
th{background:var(--card)} |
||||
blockquote{border-left:3px solid var(--accent);margin:1em 0;padding:.2em 1em;color:var(--muted);background:var(--card)} |
||||
hr{border:none;border-top:1px solid var(--border);margin:2em 0} |
||||
</style></head> |
||||
<body><div class="wrap"><h1>增量编译缓存</h1> |
||||
<p>TypePHP 的二次编译速度,很大程度上取决于<strong>对象文件缓存是否命中</strong>。编译器对两类源文件做内容指纹缓存:phpx 的 <code>misc</code> 源,以及编译器自己生成的 <code>.cc</code> 单元。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1116-L1292">src/Translator.php</a></p> |
||||
<h2>两类缓存</h2> |
||||
<table><thead><tr><th>方法</th><th>适用对象</th><th>缓存键组成</th></tr></thead><tbody><tr><td><code>hasMiscObjectFileCache()</code></td><td><code>phpx/src/misc/*.cc</code></td><td>编译命令 + PHP ABI(<code>PHP_VERSION_ID</code> / <code>ZEND_MODULE_API_NO</code> / <code>PHP_ZTS</code> / <code>PHP_INT_SIZE</code> 等)+ phpx 头文件 mtime</td></tr><tr><td><code>hasGeneratedObjectFileCache()</code></td><td>构建目录下的生成 <code>.cc</code></td><td>编译命令 + PHP ABI + <strong>所有生成头文件内容指纹</strong>(<code>func_decl.h</code> / <code>data_decl.h</code> / 各 <code>_arginfo.h</code>)</td></tr></tbody></table> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1116-L1160">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1207-L1240">src/Translator.php</a></p> |
||||
<h2>缓存键构造</h2> |
||||
<pre><code>hash('sha256', |
||||
buildCompileFileCommand(source, object) // 可复现的编译命令行 |
||||
. "\0" . serialize($abi) // PHP ABI 快照 |
||||
[. "\0" . header . "\0" . hash_file(header)] // 仅生成单元:逐头文件内容 |
||||
)</code></pre> |
||||
<p>键写入 <code><object>.typephp-cache</code> 元数据文件(<code>getMiscObjectCacheMetadataFile()</code>)。每次 <code>compileFile()</code> 先比较元数据文件中的键,再比较 <code>.o</code> 与源/头的 mtime——<strong>任一不满足即失效并重编译</strong>。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1162-L1187">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1272-L1292">src/Translator.php</a></p> |
||||
<h2>设计要点</h2> |
||||
<ul><li><strong><code>extension-<target>.cc</code> 故意不进共享头依赖</strong>:它的内容随任意类变化而改变,若纳入指纹会让每个 <code>.cc</code> 都失效,破坏增量构建。它自身作为生成单元拥有独立缓存项。</li><li><strong><code>--force</code> / <code>--profile</code> 强制失效</strong>:这两类参数会跳过全部缓存,确保 misc 文件也被重编(profiler 需 <code>PPROF_ON</code> 宏生效)。</li><li><strong>头文件依赖集排序后参与哈希</strong>,避免路径顺序差异导致误失效。</li></ul> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1242-L1271">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1218-L1226">src/Translator.php</a></p> |
||||
<h2>相关阅读</h2> |
||||
<ul><li>缓存何时被查询 → <a href="pages/build-pipeline.html">构建流水线</a></li><li>编译命令从何而来 → <a href="pages/backend.html">编译器后端</a></li><li>整体性能分析 → <a href="pages/build-speed.html">构建速度与性能</a></li></ul></div></body></html> |
||||
@ -0,0 +1,46 @@ |
||||
<blog> |
||||
|
||||
# 增量编译缓存 |
||||
|
||||
TypePHP 的二次编译速度,很大程度上取决于**对象文件缓存是否命中**。编译器对两类源文件做内容指纹缓存:phpx 的 `misc` 源,以及编译器自己生成的 `.cc` 单元。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L1116-L1292) |
||||
|
||||
## 两类缓存 |
||||
|
||||
| 方法 | 适用对象 | 缓存键组成 | |
||||
|---|---|---| |
||||
| `hasMiscObjectFileCache()` | `phpx/src/misc/*.cc` | 编译命令 + PHP ABI(`PHP_VERSION_ID` / `ZEND_MODULE_API_NO` / `PHP_ZTS` / `PHP_INT_SIZE` 等)+ phpx 头文件 mtime | |
||||
| `hasGeneratedObjectFileCache()` | 构建目录下的生成 `.cc` | 编译命令 + PHP ABI + **所有生成头文件内容指纹**(`func_decl.h` / `data_decl.h` / 各 `_arginfo.h`) | |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L1116-L1160) · [src/Translator.php](src/Translator.php#L1207-L1240) |
||||
|
||||
## 缓存键构造 |
||||
|
||||
```php |
||||
hash('sha256', |
||||
buildCompileFileCommand(source, object) // 可复现的编译命令行 |
||||
. "\0" . serialize($abi) // PHP ABI 快照 |
||||
[. "\0" . header . "\0" . hash_file(header)] // 仅生成单元:逐头文件内容 |
||||
) |
||||
``` |
||||
|
||||
键写入 `<object>.typephp-cache` 元数据文件(`getMiscObjectCacheMetadataFile()`)。每次 `compileFile()` 先比较元数据文件中的键,再比较 `.o` 与源/头的 mtime——**任一不满足即失效并重编译**。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L1162-L1187) · [src/Translator.php](src/Translator.php#L1272-L1292) |
||||
|
||||
## 设计要点 |
||||
|
||||
- **`extension-<target>.cc` 故意不进共享头依赖**:它的内容随任意类变化而改变,若纳入指纹会让每个 `.cc` 都失效,破坏增量构建。它自身作为生成单元拥有独立缓存项。 |
||||
- **`--force` / `--profile` 强制失效**:这两类参数会跳过全部缓存,确保 misc 文件也被重编(profiler 需 `PPROF_ON` 宏生效)。 |
||||
- **头文件依赖集排序后参与哈希**,避免路径顺序差异导致误失效。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L1242-L1271) · [src/Translator.php](src/Translator.php#L1218-L1226) |
||||
|
||||
## 相关阅读 |
||||
|
||||
- 缓存何时被查询 → [构建流水线](build-pipeline) |
||||
- 编译命令从何而来 → [编译器后端](backend) |
||||
- 整体性能分析 → [构建速度与性能](build-speed) |
||||
|
||||
</blog> |
||||
@ -0,0 +1,43 @@ |
||||
<!doctype html><html lang="zh"><head><meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width,initial-scale=1"> |
||||
<title>原生类型映射</title> |
||||
<script src="../script/mermaid.min.js"></script> |
||||
<script>document.addEventListener('DOMContentLoaded',function(){if(window.mermaid)mermaid.initialize({startOnLoad:true});});</script> |
||||
<style> |
||||
:root{--bg:#0f1117;--fg:#e6e6e6;--muted:#9aa0aa;--accent:#6ea8fe;--card:#171a21;--border:#262b36;} |
||||
*{box-sizing:border-box} |
||||
body{margin:0;font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background:var(--bg);color:var(--fg);line-height:1.65} |
||||
.wrap{max-width:900px;margin:0 auto;padding:32px 24px 80px} |
||||
h1,h2,h3{color:#fff;line-height:1.3;margin-top:1.6em} |
||||
h1{border-bottom:1px solid var(--border);padding-bottom:.3em} |
||||
a{color:var(--accent);text-decoration:none} |
||||
a:hover{text-decoration:underline} |
||||
code{background:#0b0d12;padding:.15em .4em;border-radius:4px;font-size:.9em} |
||||
pre{background:#0b0d12;border:1px solid var(--border);border-radius:8px;padding:14px;overflow:auto} |
||||
pre code{background:none;padding:0} |
||||
table{border-collapse:collapse;width:100%;margin:1em 0} |
||||
th,td{border:1px solid var(--border);padding:8px 10px;text-align:left} |
||||
th{background:var(--card)} |
||||
blockquote{border-left:3px solid var(--accent);margin:1em 0;padding:.2em 1em;color:var(--muted);background:var(--card)} |
||||
hr{border:none;border-top:1px solid var(--border);margin:2em 0} |
||||
</style></head> |
||||
<body><div class="wrap"><h1>原生类型映射</h1> |
||||
<p>TypePHP 的核心性能来源之一:<strong>PHP 标量直接映射 C++ 原生类型</strong>,而不是一律装箱成 <code>zval</code>。所有可发射的 C++ 类型集中在 <code>Type</code> 类(<code>src/Type.php</code>),以字符串常量形式供生成器引用。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Type.php#L5-L27">src/Type.php</a> · <a href="file:///D:\git\php\aot-compiler\docs\NATIVE_TYPES.md">docs/NATIVE_TYPES.md</a></p> |
||||
<h2>类型常量表</h2> |
||||
<table><thead><tr><th>TypePHP 类型</th><th>C++ 映射</th><th>说明</th></tr></thead><tbody><tr><td><code>int</code></td><td><code>php::Int</code></td><td>zend_long,8 字节</td></tr><tr><td><code>float</code></td><td><code>php::Float</code></td><td>double,8 字节</td></tr><tr><td><code>bool</code></td><td><code>php::Bool</code></td><td>原生 bool</td></tr><tr><td><code>string</code></td><td><code>php::Str</code></td><td>字符串</td></tr><tr><td><code>array</code></td><td><code>php::Array</code></td><td>PHP 数组</td></tr><tr><td><code>object</code></td><td><code>php::Object</code></td><td>对象</td></tr><tr><td><code>mixed</code> / 动态</td><td><code>php::Var</code></td><td>通用 zval 盒子</td></tr><tr><td><code>resource</code> / <code>stream</code></td><td><code>php::Resource</code> / <code>php::Stream</code></td><td>资源</td></tr><tr><td><code>bigInt</code> / <code>decimal</code> / <code>bigFloat</code></td><td><code>php::BigInt</code> / <code>Decimal</code> / <code>php::BigFloat</code></td><td>高精度(见 <a href="pages/high-precision-types.html">high-precision-types</a>)</td></tr><tr><td><code>std</code> 容器</td><td><code>php::StdArray/StdVector/StdMap/StdOrderedMap</code></td><td>Std 容器</td></tr></tbody></table> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Type.php#L7-L24">src/Type.php</a></p> |
||||
<h2>固定值类型属性约束</h2> |
||||
<p>AOT 要求<strong>对象属性在生命周期内保持声明类型</strong>。对 <code>int/float/bool/string/array</code> 这类固定值类型属性:</p> |
||||
<ul><li><strong>不允许</strong> <code>unset()</code> 或赋值 <code>null</code>(等价于把类型改成 null);</li><li>需要可空时显式声明 <code>?int $id = null;</code>。</li></ul> |
||||
<p>对象属性遵循静态类型规则:非空赋值需满足 <code>is-a</code> 继承关系,可用子类对象赋基类属性,反之不行。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\docs\NATIVE_TYPES.md#L19-L51">docs/NATIVE_TYPES.md</a></p> |
||||
<h2>使用前置</h2> |
||||
<p>高精度/原生类型需在文件头声明 <code>use native_types</code>(并建议 <code>declare(strict_types=1)</code>),例如:</p> |
||||
<pre><code><?php |
||||
declare(strict_types=1); |
||||
use native_types; |
||||
function main(): void { /* ... */ }</code></pre> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\docs\HIGH_PRECISION_TYPES.md#L51-L59">docs/HIGH_PRECISION_TYPES.md</a></p> |
||||
<h2>相关阅读</h2> |
||||
<ul><li>类型如何被检查与兼容判定 → <a href="pages/type-check.html">类型检查与兼容</a></li><li>高精度类型的运算语义 → <a href="pages/high-precision-types.html">高精度数值类型</a></li><li>类型如何进入 C++ 生成 → <a href="pages/generator.html">生成器总览</a></li></ul></div></body></html> |
||||
@ -0,0 +1,55 @@ |
||||
<blog> |
||||
|
||||
# 原生类型映射 |
||||
|
||||
TypePHP 的核心性能来源之一:**PHP 标量直接映射 C++ 原生类型**,而不是一律装箱成 `zval`。所有可发射的 C++ 类型集中在 `Type` 类(`src/Type.php`),以字符串常量形式供生成器引用。 |
||||
|
||||
Sources: [src/Type.php](src/Type.php#L5-L27) · [docs/NATIVE_TYPES.md](docs/NATIVE_TYPES.md) |
||||
|
||||
## 类型常量表 |
||||
|
||||
| TypePHP 类型 | C++ 映射 | 说明 | |
||||
|---|---|---| |
||||
| `int` | `php::Int` | zend_long,8 字节 | |
||||
| `float` | `php::Float` | double,8 字节 | |
||||
| `bool` | `php::Bool` | 原生 bool | |
||||
| `string` | `php::Str` | 字符串 | |
||||
| `array` | `php::Array` | PHP 数组 | |
||||
| `object` | `php::Object` | 对象 | |
||||
| `mixed` / 动态 | `php::Var` | 通用 zval 盒子 | |
||||
| `resource` / `stream` | `php::Resource` / `php::Stream` | 资源 | |
||||
| `bigInt` / `decimal` / `bigFloat` | `php::BigInt` / `Decimal` / `php::BigFloat` | 高精度(见 [high-precision-types](high-precision-types)) | |
||||
| `std` 容器 | `php::StdArray/StdVector/StdMap/StdOrderedMap` | Std 容器 | |
||||
|
||||
Sources: [src/Type.php](src/Type.php#L7-L24) |
||||
|
||||
## 固定值类型属性约束 |
||||
|
||||
AOT 要求**对象属性在生命周期内保持声明类型**。对 `int/float/bool/string/array` 这类固定值类型属性: |
||||
- **不允许** `unset()` 或赋值 `null`(等价于把类型改成 null); |
||||
- 需要可空时显式声明 `?int $id = null;`。 |
||||
|
||||
对象属性遵循静态类型规则:非空赋值需满足 `is-a` 继承关系,可用子类对象赋基类属性,反之不行。 |
||||
|
||||
Sources: [docs/NATIVE_TYPES.md](docs/NATIVE_TYPES.md#L19-L51) |
||||
|
||||
## 使用前置 |
||||
|
||||
高精度/原生类型需在文件头声明 `use native_types`(并建议 `declare(strict_types=1)`),例如: |
||||
|
||||
```php |
||||
<?php |
||||
declare(strict_types=1); |
||||
use native_types; |
||||
function main(): void { /* ... */ } |
||||
``` |
||||
|
||||
Sources: [docs/HIGH_PRECISION_TYPES.md](docs/HIGH_PRECISION_TYPES.md#L51-L59) |
||||
|
||||
## 相关阅读 |
||||
|
||||
- 类型如何被检查与兼容判定 → [类型检查与兼容](type-check) |
||||
- 高精度类型的运算语义 → [高精度数值类型](high-precision-types) |
||||
- 类型如何进入 C++ 生成 → [生成器总览](generator) |
||||
|
||||
</blog> |
||||
@ -0,0 +1,36 @@ |
||||
<!doctype html><html lang="zh"><head><meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width,initial-scale=1"> |
||||
<title>优化器</title> |
||||
<script src="../script/mermaid.min.js"></script> |
||||
<script>document.addEventListener('DOMContentLoaded',function(){if(window.mermaid)mermaid.initialize({startOnLoad:true});});</script> |
||||
<style> |
||||
:root{--bg:#0f1117;--fg:#e6e6e6;--muted:#9aa0aa;--accent:#6ea8fe;--card:#171a21;--border:#262b36;} |
||||
*{box-sizing:border-box} |
||||
body{margin:0;font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background:var(--bg);color:var(--fg);line-height:1.65} |
||||
.wrap{max-width:900px;margin:0 auto;padding:32px 24px 80px} |
||||
h1,h2,h3{color:#fff;line-height:1.3;margin-top:1.6em} |
||||
h1{border-bottom:1px solid var(--border);padding-bottom:.3em} |
||||
a{color:var(--accent);text-decoration:none} |
||||
a:hover{text-decoration:underline} |
||||
code{background:#0b0d12;padding:.15em .4em;border-radius:4px;font-size:.9em} |
||||
pre{background:#0b0d12;border:1px solid var(--border);border-radius:8px;padding:14px;overflow:auto} |
||||
pre code{background:none;padding:0} |
||||
table{border-collapse:collapse;width:100%;margin:1em 0} |
||||
th,td{border:1px solid var(--border);padding:8px 10px;text-align:left} |
||||
th{background:var(--card)} |
||||
blockquote{border-left:3px solid var(--accent);margin:1em 0;padding:.2em 1em;color:var(--muted);background:var(--card)} |
||||
hr{border:none;border-top:1px solid var(--border);margin:2em 0} |
||||
</style></head> |
||||
<body><div class="wrap"><h1>优化器</h1> |
||||
<p>TypePHP 在语义分析阶段运行一组 <strong>SSA(静态单赋值)驱动</strong>的优化器,目标是减少运行时开销与生成的 C++ 体积。优化入口与 SSA 构建分别在 <code>src/Optimizer/</code> 与 <code>src/Analysis/SsaBuilder.php</code>。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Optimizer">src/Optimizer/</a> · <a href="file:///D:\git\php\aot-compiler\src\Analysis\SsaBuilder.php">src/Analysis/SsaBuilder.php</a></p> |
||||
<h2>优化器清单</h2> |
||||
<table><thead><tr><th>类</th><th>作用</th></tr></thead><tbody><tr><td><code>SsaBuilder</code></td><td>构建 SSA 形式,为下游优化提供定义-使用链</td></tr><tr><td><code>SsaTypeOptimizer</code></td><td>基于 SSA 的类型推导,传播确定类型以去除运行时 <code>php::Var</code> 装箱</td></tr><tr><td><code>SsaPropOptimizer</code></td><td>属性类型的 SSA 推导与去虚化</td></tr><tr><td><code>FuncCallOptimizer</code></td><td>函数调用优化(内联候选、已知函数特化等)</td></tr><tr><td><code>LoopVarOptimizer</code></td><td>循环变量类型/作用域优化</td></tr></tbody></table> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Optimizer\SsaTypeOptimizer.php">src/Optimizer/SsaTypeOptimizer.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Optimizer\SsaPropOptimizer.php">src/Optimizer/SsaPropOptimizer.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Optimizer\FuncCallOptimizer.php">src/Optimizer/FuncCallOptimizer.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Optimizer\LoopVarOptimizer.php">src/Optimizer/LoopVarOptimizer.php</a></p> |
||||
<h2>与优化级别的关系</h2> |
||||
<p>命令行 <code>-O <level></code>(0–3)控制优化强度:级别越高,优化器介入越深、生成代码越紧凑,但编译期耗时也越大;<code>-d/--debug</code> 会关闭优化并加调试符号。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L234-L236">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L272-L274">src/Translator.php</a></p> |
||||
<h2>与类型系统的协同</h2> |
||||
<p>SSA 类型优化直接消费 <a href="pages/type-check.html">类型检查与兼容</a> 的判定结果——一旦推导确认某变量是固定原生类型,生成器即可发射 <code>php::Int</code> 而非通用 <code>php::Var</code>,省去 zval 装箱。这是「原生类型优先」原则在运行期的落地。</p> |
||||
<h2>相关阅读</h2> |
||||
<ul><li>类型如何判定 → <a href="pages/type-check.html">类型检查与兼容</a></li><li>编译期属性如何辅助优化 → <a href="pages/compile-time-attributes.html">编译期属性</a></li><li>整体速度瓶颈与改进 → <a href="pages/build-speed.html">构建速度与性能</a></li></ul></div></body></html> |
||||
@ -0,0 +1,37 @@ |
||||
<blog> |
||||
|
||||
# 优化器 |
||||
|
||||
TypePHP 在语义分析阶段运行一组 **SSA(静态单赋值)驱动**的优化器,目标是减少运行时开销与生成的 C++ 体积。优化入口与 SSA 构建分别在 `src/Optimizer/` 与 `src/Analysis/SsaBuilder.php`。 |
||||
|
||||
Sources: [src/Optimizer/](src/Optimizer/) · [src/Analysis/SsaBuilder.php](src/Analysis/SsaBuilder.php) |
||||
|
||||
## 优化器清单 |
||||
|
||||
| 类 | 作用 | |
||||
|---|---| |
||||
| `SsaBuilder` | 构建 SSA 形式,为下游优化提供定义-使用链 | |
||||
| `SsaTypeOptimizer` | 基于 SSA 的类型推导,传播确定类型以去除运行时 `php::Var` 装箱 | |
||||
| `SsaPropOptimizer` | 属性类型的 SSA 推导与去虚化 | |
||||
| `FuncCallOptimizer` | 函数调用优化(内联候选、已知函数特化等) | |
||||
| `LoopVarOptimizer` | 循环变量类型/作用域优化 | |
||||
|
||||
Sources: [src/Optimizer/SsaTypeOptimizer.php](src/Optimizer/SsaTypeOptimizer.php) · [src/Optimizer/SsaPropOptimizer.php](src/Optimizer/SsaPropOptimizer.php) · [src/Optimizer/FuncCallOptimizer.php](src/Optimizer/FuncCallOptimizer.php) · [src/Optimizer/LoopVarOptimizer.php](src/Optimizer/LoopVarOptimizer.php) |
||||
|
||||
## 与优化级别的关系 |
||||
|
||||
命令行 `-O <level>`(0–3)控制优化强度:级别越高,优化器介入越深、生成代码越紧凑,但编译期耗时也越大;`-d/--debug` 会关闭优化并加调试符号。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L234-L236) · [src/Translator.php](src/Translator.php#L272-L274) |
||||
|
||||
## 与类型系统的协同 |
||||
|
||||
SSA 类型优化直接消费 [类型检查与兼容](type-check) 的判定结果——一旦推导确认某变量是固定原生类型,生成器即可发射 `php::Int` 而非通用 `php::Var`,省去 zval 装箱。这是「原生类型优先」原则在运行期的落地。 |
||||
|
||||
## 相关阅读 |
||||
|
||||
- 类型如何判定 → [类型检查与兼容](type-check) |
||||
- 编译期属性如何辅助优化 → [编译期属性](compile-time-attributes) |
||||
- 整体速度瓶颈与改进 → [构建速度与性能](build-speed) |
||||
|
||||
</blog> |
||||
@ -0,0 +1,35 @@ |
||||
<!doctype html><html lang="zh"><head><meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width,initial-scale=1"> |
||||
<title>项目简介</title> |
||||
<script src="../script/mermaid.min.js"></script> |
||||
<script>document.addEventListener('DOMContentLoaded',function(){if(window.mermaid)mermaid.initialize({startOnLoad:true});});</script> |
||||
<style> |
||||
:root{--bg:#0f1117;--fg:#e6e6e6;--muted:#9aa0aa;--accent:#6ea8fe;--card:#171a21;--border:#262b36;} |
||||
*{box-sizing:border-box} |
||||
body{margin:0;font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background:var(--bg);color:var(--fg);line-height:1.65} |
||||
.wrap{max-width:900px;margin:0 auto;padding:32px 24px 80px} |
||||
h1,h2,h3{color:#fff;line-height:1.3;margin-top:1.6em} |
||||
h1{border-bottom:1px solid var(--border);padding-bottom:.3em} |
||||
a{color:var(--accent);text-decoration:none} |
||||
a:hover{text-decoration:underline} |
||||
code{background:#0b0d12;padding:.15em .4em;border-radius:4px;font-size:.9em} |
||||
pre{background:#0b0d12;border:1px solid var(--border);border-radius:8px;padding:14px;overflow:auto} |
||||
pre code{background:none;padding:0} |
||||
table{border-collapse:collapse;width:100%;margin:1em 0} |
||||
th,td{border:1px solid var(--border);padding:8px 10px;text-align:left} |
||||
th{background:var(--card)} |
||||
blockquote{border-left:3px solid var(--accent);margin:1em 0;padding:.2em 1em;color:var(--muted);background:var(--card)} |
||||
hr{border:none;border-top:1px solid var(--border);margin:2em 0} |
||||
</style></head> |
||||
<body><div class="wrap"><h1>项目简介</h1> |
||||
<p><strong>TypePHP</strong> 是 Swoole 团队开发的 <strong>PHP 原生 AOT 编译器</strong>(仓库名 <code>aot-compiler</code>,Composer 包名 <code>swoole/typephp</code>)。它把 PHP 源码在编译期直接翻译成 <strong>C++</strong>,再借助 PHPX 运行时与 Zend 引擎嵌入(<code>embed</code>)能力,链接为 <strong>Windows / Linux / macOS</strong> 平台原生的可执行文件、共享库或 PHP 扩展。</p> |
||||
<p>当前版本 <code>v0.4.3</code>(见 <code>src/Translator.php</code> 常量 <code>VERSION</code>)。编译器自身需要 <strong>PHP 8.4+</strong>;生成的产物可面向 <strong>PHP 8.2 ~ 8.5</strong> 的运行时语义。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\composer.json#L2-L4">composer.json</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L61-L62">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\README.md#L1-L6">README.md</a></p> |
||||
<h2>为什么不是解释执行</h2> |
||||
<p>传统 PHP 每次运行都要经过「词法 → 语法 → 字节码 → Zend 解释」四步。TypePHP 把前两步(以及大量语义分析)在编译期一次性完成,生成的 C++ 再被优化编译器(GCC/Clang/MSVC)进一步内联、逃逸分析与向量化,最终产出的二进制<strong>不再依赖 <code>php</code> 解释器即可运行</strong>——只依赖编译进来的 Zend 引擎(<code>libphp.so</code> / <code>php8ts.lib</code>)。</p> |
||||
<blockquote>注意:预览版目前<strong>仅支持 Linux</strong>(建议 Ubuntu 22.04),Windows 编译需在具备 Windows SDK 与 PHP embed 库的环境下进行。</blockquote> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\README.md#L42-L43">README.md</a> · <a href="file:///D:\git\php\aot-compiler\composer.json#L8-L16">composer.json</a></p> |
||||
<h2>设计原则</h2> |
||||
<ul><li><strong>原生类型优先</strong>:标量(int/float/bool/string)直接映射 C++ 原生类型,避免 zval 装箱开销。</li><li><strong>PHP 语义对齐</strong>:类、接口、trait、枚举、反射、属性(attribute)、生成器(Generator)等尽量保持运行时行为。</li><li><strong>可增量构建</strong>:phpx misc 文件与编译器生成单元都带内容指纹缓存,改动一处不必全量重编译。</li></ul> |
||||
<h2>阅读路线</h2> |
||||
<ul><li>想了解「PHP 如何一步步变成二进制」→ <a href="pages/pipeline.html">编译流水线</a></li><li>想区分三种产物形态 → <a href="pages/compilation-modes.html">编译模式</a></li><li>想立刻跑通一个例子 → <a href="pages/quickstart.html">快速开始</a></li><li>想深入每个子系统 → 依次阅读 <a href="pages/parser.html">解析器与 AST</a> → <a href="pages/preprocessor.html">预处理与符号表</a> → <a href="pages/transform.html">AST 转换</a> → <a href="pages/generator.html">代码生成</a></li></ul></div></body></html> |
||||
@ -0,0 +1,32 @@ |
||||
<blog> |
||||
|
||||
# 项目简介 |
||||
|
||||
**TypePHP** 是 Swoole 团队开发的 **PHP 原生 AOT 编译器**(仓库名 `aot-compiler`,Composer 包名 `swoole/typephp`)。它把 PHP 源码在编译期直接翻译成 **C++**,再借助 PHPX 运行时与 Zend 引擎嵌入(`embed`)能力,链接为 **Windows / Linux / macOS** 平台原生的可执行文件、共享库或 PHP 扩展。 |
||||
|
||||
当前版本 `v0.4.3`(见 `src/Translator.php` 常量 `VERSION`)。编译器自身需要 **PHP 8.4+**;生成的产物可面向 **PHP 8.2 ~ 8.5** 的运行时语义。 |
||||
|
||||
Sources: [composer.json](composer.json#L2-L4) · [src/Translator.php](src/Translator.php#L61-L62) · [README.md](README.md#L1-L6) |
||||
|
||||
## 为什么不是解释执行 |
||||
|
||||
传统 PHP 每次运行都要经过「词法 → 语法 → 字节码 → Zend 解释」四步。TypePHP 把前两步(以及大量语义分析)在编译期一次性完成,生成的 C++ 再被优化编译器(GCC/Clang/MSVC)进一步内联、逃逸分析与向量化,最终产出的二进制**不再依赖 `php` 解释器即可运行**——只依赖编译进来的 Zend 引擎(`libphp.so` / `php8ts.lib`)。 |
||||
|
||||
> 注意:预览版目前**仅支持 Linux**(建议 Ubuntu 22.04),Windows 编译需在具备 Windows SDK 与 PHP embed 库的环境下进行。 |
||||
|
||||
Sources: [README.md](README.md#L42-L43) · [composer.json](composer.json#L8-L16) |
||||
|
||||
## 设计原则 |
||||
|
||||
- **原生类型优先**:标量(int/float/bool/string)直接映射 C++ 原生类型,避免 zval 装箱开销。 |
||||
- **PHP 语义对齐**:类、接口、trait、枚举、反射、属性(attribute)、生成器(Generator)等尽量保持运行时行为。 |
||||
- **可增量构建**:phpx misc 文件与编译器生成单元都带内容指纹缓存,改动一处不必全量重编译。 |
||||
|
||||
## 阅读路线 |
||||
|
||||
- 想了解「PHP 如何一步步变成二进制」→ [编译流水线](pipeline) |
||||
- 想区分三种产物形态 → [编译模式](compilation-modes) |
||||
- 想立刻跑通一个例子 → [快速开始](quickstart) |
||||
- 想深入每个子系统 → 依次阅读 [解析器与 AST](parser) → [预处理与符号表](preprocessor) → [AST 转换](transform) → [代码生成](generator) |
||||
|
||||
</blog> |
||||
@ -0,0 +1,45 @@ |
||||
<!doctype html><html lang="zh"><head><meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width,initial-scale=1"> |
||||
<title>解析器与 AST</title> |
||||
<script src="../script/mermaid.min.js"></script> |
||||
<script>document.addEventListener('DOMContentLoaded',function(){if(window.mermaid)mermaid.initialize({startOnLoad:true});});</script> |
||||
<style> |
||||
:root{--bg:#0f1117;--fg:#e6e6e6;--muted:#9aa0aa;--accent:#6ea8fe;--card:#171a21;--border:#262b36;} |
||||
*{box-sizing:border-box} |
||||
body{margin:0;font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background:var(--bg);color:var(--fg);line-height:1.65} |
||||
.wrap{max-width:900px;margin:0 auto;padding:32px 24px 80px} |
||||
h1,h2,h3{color:#fff;line-height:1.3;margin-top:1.6em} |
||||
h1{border-bottom:1px solid var(--border);padding-bottom:.3em} |
||||
a{color:var(--accent);text-decoration:none} |
||||
a:hover{text-decoration:underline} |
||||
code{background:#0b0d12;padding:.15em .4em;border-radius:4px;font-size:.9em} |
||||
pre{background:#0b0d12;border:1px solid var(--border);border-radius:8px;padding:14px;overflow:auto} |
||||
pre code{background:none;padding:0} |
||||
table{border-collapse:collapse;width:100%;margin:1em 0} |
||||
th,td{border:1px solid var(--border);padding:8px 10px;text-align:left} |
||||
th{background:var(--card)} |
||||
blockquote{border-left:3px solid var(--accent);margin:1em 0;padding:.2em 1em;color:var(--muted);background:var(--card)} |
||||
hr{border:none;border-top:1px solid var(--border);margin:2em 0} |
||||
</style></head> |
||||
<body><div class="wrap"><h1>解析器与 AST</h1> |
||||
<p>TypePHP 复用 <strong>nikic/php-parser</strong> 作为前端词法/语法分析器(依赖固定版本 <code>5.6.1</code>)。解析得到的 PHP AST 是后续所有翻译与符号收集的输入。本章说明 AST 从何而来、以何种形态进入编译器。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\composer.json#L10">composer.json</a> · <a href="file:///D:\git\php\aot-compiler\project.yml#L34-L35">project.yml</a></p> |
||||
<h2>AST 来源</h2> |
||||
<p>解析发生在两个时机:</p> |
||||
<ol><li><strong>预处理阶段</strong>:<code>Preprocessor::prepareFile()</code> 解析每个 PHP 文件,收集类/函数/常量/属性等符号,构建全局符号表(详见 <a href="pages/preprocessor.html">预处理与符号表</a>)。</li><li><strong>转换阶段</strong>:<code>doConvert()</code> 通过 <code>parseCachedAst()</code> 解析同一文件,得到供代码生成的 AST。</li></ol> |
||||
<blockquote><code>parseCachedAst()</code> 做了两层缓存——同一文件的 AST 在进程内复用,避免重复解析;这也是编译性能优化(S1)的关键点之一。</blockquote> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Preprocessor.php#L116">src/Preprocessor.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L2459">src/Translator.php</a></p> |
||||
<h2>表达式翻译:Parser Trait 集合</h2> |
||||
<p>编译器主体 <code>CompilerBase</code> 并未把「PHP 表达式 → C++」的逻辑塞进一个巨型方法,而是拆成 <code>src/Parser/</code> 下的 <strong>21 个 trait</strong>,每个 trait 负责一类语法结构:</p> |
||||
<table><thead><tr><th>Trait</th><th>负责的 PHP 结构</th></tr></thead><tbody><tr><td><code>BinaryOpTrait</code></td><td><code>+ - * /</code> 等二元运算</td></tr><tr><td><code>AssignOpTrait</code></td><td><code>+=</code>、<code>??=</code> 等复合赋值</td></tr><tr><td><code>UnaryExpressionTrait</code></td><td><code>!</code>、<code>-</code>、<code>++</code> 等一元运算</td></tr><tr><td><code>FunctionCallTrait</code></td><td>普通函数调用</td></tr><tr><td><code>MethodCallTrait</code> / <code>UniversalMethodCall</code></td><td>对象/静态方法调用</td></tr><tr><td><code>PropertyAccessTrait</code></td><td>属性读写</td></tr><tr><td><code>ArrayExpressionTrait</code></td><td>数组字面量</td></tr><tr><td><code>ForeachTrait</code> / <code>LoopControlTrait</code></td><td><code>foreach</code> / <code>for</code> / <code>while</code></td></tr><tr><td><code>SelectionExpressionTrait</code> / <code>SwitchTrait</code></td><td><code>if</code> / <code>switch</code></td></tr><tr><td><code>ConditionalControlTrait</code></td><td><code>?:</code> / <code>match</code></td></tr><tr><td><code>NullsafeAccessTrait</code></td><td><code>?-></code></td></tr><tr><td><code>ClassConstantFetchTrait</code></td><td>类常量读取</td></tr><tr><td><code>TypeConversionTrait</code> / <code>TypeDetectionTrait</code></td><td>类型转换与 <code>instanceof</code></td></tr><tr><td><code>ConstantExpressionTrait</code></td><td>编译期常量折叠</td></tr><tr><td><code>ExceptionControlFlowTrait</code></td><td><code>try/catch/throw</code></td></tr><tr><td><code>StdContainerTrait</code></td><td><code>std</code> 容器操作</td></tr></tbody></table> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\CompilerBase.php#L43-L63">src/CompilerBase.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Parser">src/Parser/</a></p> |
||||
<h2>访客链</h2> |
||||
<p><code>doConvert()</code> 在遍历 AST 前先挂载四个 <code>NodeVisitor</code>:</p> |
||||
<pre><code>$traverser->addVisitor(new NameResolver(...)); // 全限定名解析 |
||||
$traverser->addVisitor(new Visitor(...)); // Transform lowering(见 transform) |
||||
$traverser->addVisitor(new ConstantExpressionValidationVisitor(...)); |
||||
$traverser->addVisitor(new RuntimeAttributeFactoryLowering(...));</code></pre> |
||||
<p><code>NameResolver</code> 把短名解析为全限定名(但不替换节点),让后续生成能拿到准确的命名空间路径。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L2460-L2467">src/Translator.php</a></p> |
||||
<h2>相关阅读</h2> |
||||
<ul><li>符号如何被收集 → <a href="pages/preprocessor.html">预处理与符号表</a></li><li>遍历中做了哪些改写 → <a href="pages/transform.html">AST 转换</a></li><li>解析结果的消费方 → <a href="pages/generator.html">代码生成</a></li></ul></div></body></html> |
||||
@ -0,0 +1,66 @@ |
||||
<blog> |
||||
|
||||
# 解析器与 AST |
||||
|
||||
TypePHP 复用 **nikic/php-parser** 作为前端词法/语法分析器(依赖固定版本 `5.6.1`)。解析得到的 PHP AST 是后续所有翻译与符号收集的输入。本章说明 AST 从何而来、以何种形态进入编译器。 |
||||
|
||||
Sources: [composer.json](composer.json#L10) · [project.yml](project.yml#L34-L35) |
||||
|
||||
## AST 来源 |
||||
|
||||
解析发生在两个时机: |
||||
|
||||
1. **预处理阶段**:`Preprocessor::prepareFile()` 解析每个 PHP 文件,收集类/函数/常量/属性等符号,构建全局符号表(详见 [预处理与符号表](preprocessor))。 |
||||
2. **转换阶段**:`doConvert()` 通过 `parseCachedAst()` 解析同一文件,得到供代码生成的 AST。 |
||||
|
||||
> `parseCachedAst()` 做了两层缓存——同一文件的 AST 在进程内复用,避免重复解析;这也是编译性能优化(S1)的关键点之一。 |
||||
|
||||
Sources: [src/Preprocessor.php](src/Preprocessor.php#L116) · [src/Translator.php](src/Translator.php#L2459) |
||||
|
||||
## 表达式翻译:Parser Trait 集合 |
||||
|
||||
编译器主体 `CompilerBase` 并未把「PHP 表达式 → C++」的逻辑塞进一个巨型方法,而是拆成 `src/Parser/` 下的 **21 个 trait**,每个 trait 负责一类语法结构: |
||||
|
||||
| Trait | 负责的 PHP 结构 | |
||||
|---|---| |
||||
| `BinaryOpTrait` | `+ - * /` 等二元运算 | |
||||
| `AssignOpTrait` | `+=`、`??=` 等复合赋值 | |
||||
| `UnaryExpressionTrait` | `!`、`-`、`++` 等一元运算 | |
||||
| `FunctionCallTrait` | 普通函数调用 | |
||||
| `MethodCallTrait` / `UniversalMethodCall` | 对象/静态方法调用 | |
||||
| `PropertyAccessTrait` | 属性读写 | |
||||
| `ArrayExpressionTrait` | 数组字面量 | |
||||
| `ForeachTrait` / `LoopControlTrait` | `foreach` / `for` / `while` | |
||||
| `SelectionExpressionTrait` / `SwitchTrait` | `if` / `switch` | |
||||
| `ConditionalControlTrait` | `?:` / `match` | |
||||
| `NullsafeAccessTrait` | `?->` | |
||||
| `ClassConstantFetchTrait` | 类常量读取 | |
||||
| `TypeConversionTrait` / `TypeDetectionTrait` | 类型转换与 `instanceof` | |
||||
| `ConstantExpressionTrait` | 编译期常量折叠 | |
||||
| `ExceptionControlFlowTrait` | `try/catch/throw` | |
||||
| `StdContainerTrait` | `std` 容器操作 | |
||||
|
||||
Sources: [src/CompilerBase.php](src/CompilerBase.php#L43-L63) · [src/Parser/](src/Parser/) |
||||
|
||||
## 访客链 |
||||
|
||||
`doConvert()` 在遍历 AST 前先挂载四个 `NodeVisitor`: |
||||
|
||||
```php |
||||
$traverser->addVisitor(new NameResolver(...)); // 全限定名解析 |
||||
$traverser->addVisitor(new Visitor(...)); // Transform lowering(见 transform) |
||||
$traverser->addVisitor(new ConstantExpressionValidationVisitor(...)); |
||||
$traverser->addVisitor(new RuntimeAttributeFactoryLowering(...)); |
||||
``` |
||||
|
||||
`NameResolver` 把短名解析为全限定名(但不替换节点),让后续生成能拿到准确的命名空间路径。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L2460-L2467) |
||||
|
||||
## 相关阅读 |
||||
|
||||
- 符号如何被收集 → [预处理与符号表](preprocessor) |
||||
- 遍历中做了哪些改写 → [AST 转换](transform) |
||||
- 解析结果的消费方 → [代码生成](generator) |
||||
|
||||
</blog> |
||||
@ -0,0 +1,48 @@ |
||||
<!doctype html><html lang="zh"><head><meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width,initial-scale=1"> |
||||
<title>编译流水线</title> |
||||
<script src="../script/mermaid.min.js"></script> |
||||
<script>document.addEventListener('DOMContentLoaded',function(){if(window.mermaid)mermaid.initialize({startOnLoad:true});});</script> |
||||
<style> |
||||
:root{--bg:#0f1117;--fg:#e6e6e6;--muted:#9aa0aa;--accent:#6ea8fe;--card:#171a21;--border:#262b36;} |
||||
*{box-sizing:border-box} |
||||
body{margin:0;font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background:var(--bg);color:var(--fg);line-height:1.65} |
||||
.wrap{max-width:900px;margin:0 auto;padding:32px 24px 80px} |
||||
h1,h2,h3{color:#fff;line-height:1.3;margin-top:1.6em} |
||||
h1{border-bottom:1px solid var(--border);padding-bottom:.3em} |
||||
a{color:var(--accent);text-decoration:none} |
||||
a:hover{text-decoration:underline} |
||||
code{background:#0b0d12;padding:.15em .4em;border-radius:4px;font-size:.9em} |
||||
pre{background:#0b0d12;border:1px solid var(--border);border-radius:8px;padding:14px;overflow:auto} |
||||
pre code{background:none;padding:0} |
||||
table{border-collapse:collapse;width:100%;margin:1em 0} |
||||
th,td{border:1px solid var(--border);padding:8px 10px;text-align:left} |
||||
th{background:var(--card)} |
||||
blockquote{border-left:3px solid var(--accent);margin:1em 0;padding:.2em 1em;color:var(--muted);background:var(--card)} |
||||
hr{border:none;border-top:1px solid var(--border);margin:2em 0} |
||||
</style></head> |
||||
<body><div class="wrap"><h1>编译流水线</h1> |
||||
<p>TypePHP 的核心入口是 <code>bin/tpc.php</code>,它通过 <code>main()</code> 串起整条流水线:<code>prepare → convert → compile → build → run</code>。本章用一张图和一个阶段表把全链路讲清楚。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\bin\tpc.php#L1-L9">bin/tpc.php</a> · <a href="file:///D:\git\php\aot-compiler\src\compiler.php#L4-L46">src/compiler.php</a></p> |
||||
<h2>总体流程</h2> |
||||
<pre class="mermaid">flowchart TD |
||||
A["main(argc, argv)"] --> B["prepare(argv)\n扫描 PHP 文件 + 预处理"] |
||||
B --> C["convert(files)\nPHP AST → C++ 源文件"] |
||||
C --> D{"--dry?"} |
||||
D -- "是" --> Z["仅输出 C++,结束"] |
||||
D -- "否" --> E["compile(sourceFiles)\nC++ → .o / .obj"] |
||||
E --> F["build(objectFiles)\n链接为二进制 / 库 / 扩展"] |
||||
F --> G{"--run?"} |
||||
G -- "是" --> H["run(binary)\n立即执行"] |
||||
G -- "否" --> Z</pre> |
||||
<p><code>.prof</code> 后缀会被切换为 <code>profileAnalyze</code> 模式,调用 <code>pprof --web</code> 做性能剖析。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\compiler.php#L14-L18">src/compiler.php</a> · <a href="file:///D:\git\php\aot-compiler\src\compiler.php#L26-L45">src/compiler.php</a></p> |
||||
<h2>各阶段职责</h2> |
||||
<table><thead><tr><th>阶段</th><th>方法</th><th>关键工作</th></tr></thead><tbody><tr><td>准备</td><td><code>Translator::prepare()</code></td><td>扫描所有 PHP 文件、解析命令行、构建符号表(类/函数/常量/属性)</td></tr><tr><td>转换</td><td><code>Translator::convert()</code> → <code>convertFile()</code> → <code>doConvert()</code></td><td>对每个 PHP 文件解析 AST,跑 Transform 访客,生成 <code>.cc</code> 与 <code>_arginfo.h</code></td></tr><tr><td>编译</td><td><code>Translator::compile()</code></td><td>追加 phpx misc 源文件、准备 PCH、单进程或 <code>pcntl</code> 并行编译</td></tr><tr><td>构建</td><td><code>Translator::build()</code></td><td>调用原生链接器把目标文件 + 资源文件链接成最终产物</td></tr><tr><td>运行</td><td><code>Translator::run()</code></td><td>仅在 <code>bin</code> 模式且带 <code>--run</code> 时执行产物</td></tr></tbody></table> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L504-L527">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1419-L1447">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1649-L1680">src/Translator.php</a></p> |
||||
<h2>转换阶段的两趟扫描</h2> |
||||
<p><code>doConvert()</code> 内部做了两件事(<a href="file:///D:\git\php\aot-compiler\src\Translator.php#L2455-L2537">src/Translator.php</a>):</p> |
||||
<ol><li><strong>AST 遍历</strong>:用 <code>NodeTraverser</code> 串联 <code>NameResolver</code>、<code>Transform\Visitor</code>、<code>ConstantExpressionValidationVisitor</code>、<code>RuntimeAttributeFactoryLowering</code> 四个访客,做名称解析、编译期属性 lowering、常量表达式校验。</li><li><strong>语句分发</strong>:遍历顶层语句,按 <code>Stmt_Class</code> / <code>Stmt_Function</code> / <code>Stmt_Const</code> 等类型调用对应的 <code>parseXxx()</code>,最后为每个类、接口、函数生成 C++ 包装代码(<code>genClassWrapper</code> / <code>genFunctionWrapper</code>)。</li></ol> |
||||
<blockquote>前端的解析/符号表逻辑在 <a href="pages/preprocessor.html">preprocessor</a> 与 <a href="pages/transform.html">transform</a> 章节展开;C++ 生成细节在 <a href="pages/generator.html">generator</a>。</blockquote> |
||||
<h2>关键文件</h2> |
||||
<ul><li><code>src/compiler.php</code> — 顶层 <code>main()</code> 与 <code>.prof</code> 剖析模式。</li><li><code>src/Translator.php</code> — 流水线编排 + 构建/链接/缓存。</li><li><code>src/Preprocessor.php</code> / <code>src/CompilerBase.php</code> — 解析、符号收集、C++ 代码发射(占 7000+ 行,是编译器主体)。</li></ul></div></body></html> |
||||
@ -0,0 +1,55 @@ |
||||
<blog> |
||||
|
||||
# 编译流水线 |
||||
|
||||
TypePHP 的核心入口是 `bin/tpc.php`,它通过 `main()` 串起整条流水线:`prepare → convert → compile → build → run`。本章用一张图和一个阶段表把全链路讲清楚。 |
||||
|
||||
Sources: [bin/tpc.php](bin/tpc.php#L1-L9) · [src/compiler.php](src/compiler.php#L4-L46) |
||||
|
||||
## 总体流程 |
||||
|
||||
```mermaid |
||||
flowchart TD |
||||
A["main(argc, argv)"] --> B["prepare(argv)\n扫描 PHP 文件 + 预处理"] |
||||
B --> C["convert(files)\nPHP AST → C++ 源文件"] |
||||
C --> D{"--dry?"} |
||||
D -- "是" --> Z["仅输出 C++,结束"] |
||||
D -- "否" --> E["compile(sourceFiles)\nC++ → .o / .obj"] |
||||
E --> F["build(objectFiles)\n链接为二进制 / 库 / 扩展"] |
||||
F --> G{"--run?"} |
||||
G -- "是" --> H["run(binary)\n立即执行"] |
||||
G -- "否" --> Z |
||||
``` |
||||
|
||||
`.prof` 后缀会被切换为 `profileAnalyze` 模式,调用 `pprof --web` 做性能剖析。 |
||||
|
||||
Sources: [src/compiler.php](src/compiler.php#L14-L18) · [src/compiler.php](src/compiler.php#L26-L45) |
||||
|
||||
## 各阶段职责 |
||||
|
||||
| 阶段 | 方法 | 关键工作 | |
||||
|---|---|---| |
||||
| 准备 | `Translator::prepare()` | 扫描所有 PHP 文件、解析命令行、构建符号表(类/函数/常量/属性) | |
||||
| 转换 | `Translator::convert()` → `convertFile()` → `doConvert()` | 对每个 PHP 文件解析 AST,跑 Transform 访客,生成 `.cc` 与 `_arginfo.h` | |
||||
| 编译 | `Translator::compile()` | 追加 phpx misc 源文件、准备 PCH、单进程或 `pcntl` 并行编译 | |
||||
| 构建 | `Translator::build()` | 调用原生链接器把目标文件 + 资源文件链接成最终产物 | |
||||
| 运行 | `Translator::run()` | 仅在 `bin` 模式且带 `--run` 时执行产物 | |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L504-L527) · [src/Translator.php](src/Translator.php#L1419-L1447) · [src/Translator.php](src/Translator.php#L1649-L1680) |
||||
|
||||
## 转换阶段的两趟扫描 |
||||
|
||||
`doConvert()` 内部做了两件事([src/Translator.php](src/Translator.php#L2455-L2537)): |
||||
|
||||
1. **AST 遍历**:用 `NodeTraverser` 串联 `NameResolver`、`Transform\Visitor`、`ConstantExpressionValidationVisitor`、`RuntimeAttributeFactoryLowering` 四个访客,做名称解析、编译期属性 lowering、常量表达式校验。 |
||||
2. **语句分发**:遍历顶层语句,按 `Stmt_Class` / `Stmt_Function` / `Stmt_Const` 等类型调用对应的 `parseXxx()`,最后为每个类、接口、函数生成 C++ 包装代码(`genClassWrapper` / `genFunctionWrapper`)。 |
||||
|
||||
> 前端的解析/符号表逻辑在 [preprocessor](preprocessor) 与 [transform](transform) 章节展开;C++ 生成细节在 [generator](generator)。 |
||||
|
||||
## 关键文件 |
||||
|
||||
- `src/compiler.php` — 顶层 `main()` 与 `.prof` 剖析模式。 |
||||
- `src/Translator.php` — 流水线编排 + 构建/链接/缓存。 |
||||
- `src/Preprocessor.php` / `src/CompilerBase.php` — 解析、符号收集、C++ 代码发射(占 7000+ 行,是编译器主体)。 |
||||
|
||||
</blog> |
||||
@ -0,0 +1,41 @@ |
||||
<!doctype html><html lang="zh"><head><meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width,initial-scale=1"> |
||||
<title>跨平台支持</title> |
||||
<script src="../script/mermaid.min.js"></script> |
||||
<script>document.addEventListener('DOMContentLoaded',function(){if(window.mermaid)mermaid.initialize({startOnLoad:true});});</script> |
||||
<style> |
||||
:root{--bg:#0f1117;--fg:#e6e6e6;--muted:#9aa0aa;--accent:#6ea8fe;--card:#171a21;--border:#262b36;} |
||||
*{box-sizing:border-box} |
||||
body{margin:0;font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background:var(--bg);color:var(--fg);line-height:1.65} |
||||
.wrap{max-width:900px;margin:0 auto;padding:32px 24px 80px} |
||||
h1,h2,h3{color:#fff;line-height:1.3;margin-top:1.6em} |
||||
h1{border-bottom:1px solid var(--border);padding-bottom:.3em} |
||||
a{color:var(--accent);text-decoration:none} |
||||
a:hover{text-decoration:underline} |
||||
code{background:#0b0d12;padding:.15em .4em;border-radius:4px;font-size:.9em} |
||||
pre{background:#0b0d12;border:1px solid var(--border);border-radius:8px;padding:14px;overflow:auto} |
||||
pre code{background:none;padding:0} |
||||
table{border-collapse:collapse;width:100%;margin:1em 0} |
||||
th,td{border:1px solid var(--border);padding:8px 10px;text-align:left} |
||||
th{background:var(--card)} |
||||
blockquote{border-left:3px solid var(--accent);margin:1em 0;padding:.2em 1em;color:var(--muted);background:var(--card)} |
||||
hr{border:none;border-top:1px solid var(--border);margin:2em 0} |
||||
</style></head> |
||||
<body><div class="wrap"><h1>跨平台支持</h1> |
||||
<p>TypePHP 目标 <strong>Windows / Linux / macOS</strong> 三大桌面平台,通过 <code>Platform</code> 抽象隔离系统差异(编译器名、目标扩展名、PHP embed 库查找等)。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L164-L190">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Platform">src/Platform/</a></p> |
||||
<h2>平台抽象</h2> |
||||
<p><code>PlatformFactory::create()</code> 按 OS 返回具体 <code>Platform</code> 对象(Windows / Linux / macOS)。<code>detectPlatform()</code> 在 <code>Translator</code> 构造时调用,得到平台名 + 后端名(如 <code>Windows + MSVC</code>)。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L164-L190">src/Translator.php</a></p> |
||||
<h2>各平台要点</h2> |
||||
<table><thead><tr><th>平台</th><th>默认后端</th><th>链接产物</th><th>特殊点</th></tr></thead><tbody><tr><td>Linux</td><td>GCC/Clang</td><td>ELF 可执行 / <code>.so</code></td><td>推荐 Ubuntu 22.04,需 <code>libphp.so</code></td></tr><tr><td>macOS</td><td>Clang</td><td>Mach-O / <code>.dylib</code></td><td><code>strip</code> 可选</td></tr><tr><td>Windows</td><td>MSVC</td><td>PE <code>.exe</code> / <code>.dll</code></td><td>需 Windows SDK + <code>php8ts.lib</code>;资源文件编译</td></tr></tbody></table> |
||||
<p>Windows 分支会额外 <code>detectPhpLibs()</code> 探测 embed 与 core 的 <code>.lib</code>,并把 <code>isZts</code>、SDK 路径注入 <code>Windows</code> 对象。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L170-L181">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\README.md#L42-L43">README.md</a></p> |
||||
<h2>Windows 资源文件</h2> |
||||
<p><code>bin</code> 模式在 Windows 下编译 <code>.rc</code>(图标、版本信息、UAC 等,由 <code>project.yml</code> 的 <code>resource</code> 配置),生成的 <code>.res</code> 在 <code>build()</code> 链接时并入。资源文件生成见 <code>Generator/ResourceFileGenerator</code> 与 <code>Build/ResourceCompilationTrait</code>。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\project.yml#L10-L24">project.yml</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1653-L1659">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Build\ResourceCompilationTrait.php">src/Build/ResourceCompilationTrait.php</a></p> |
||||
<h2>libphp.so 自动安装</h2> |
||||
<p>Linux 缺 <code>libphp.so</code> 时,<code>tpc.php</code> 可交互式下载 PHP 源码并自动构建,详见 <code>docs/LIBPHP_INSTALLER.md</code>;安装器逻辑在 <code>src/Installer/</code>。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\README.md#L27">README.md</a> · <a href="file:///D:\git\php\aot-compiler\src\Installer">src/Installer/</a></p> |
||||
<h2>相关阅读</h2> |
||||
<ul><li>后端命令如何生成 → <a href="pages/backend.html">编译器后端</a></li><li>链接与资源并入 → <a href="pages/build-pipeline.html">构建流水线</a></li><li>二进制打包(UPX/strip) → README 的 Release packaging 段</li></ul></div></body></html> |
||||
@ -0,0 +1,45 @@ |
||||
<blog> |
||||
|
||||
# 跨平台支持 |
||||
|
||||
TypePHP 目标 **Windows / Linux / macOS** 三大桌面平台,通过 `Platform` 抽象隔离系统差异(编译器名、目标扩展名、PHP embed 库查找等)。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L164-L190) · [src/Platform/](src/Platform/) |
||||
|
||||
## 平台抽象 |
||||
|
||||
`PlatformFactory::create()` 按 OS 返回具体 `Platform` 对象(Windows / Linux / macOS)。`detectPlatform()` 在 `Translator` 构造时调用,得到平台名 + 后端名(如 `Windows + MSVC`)。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L164-L190) |
||||
|
||||
## 各平台要点 |
||||
|
||||
| 平台 | 默认后端 | 链接产物 | 特殊点 | |
||||
|---|---|---|---| |
||||
| Linux | GCC/Clang | ELF 可执行 / `.so` | 推荐 Ubuntu 22.04,需 `libphp.so` | |
||||
| macOS | Clang | Mach-O / `.dylib` | `strip` 可选 | |
||||
| Windows | MSVC | PE `.exe` / `.dll` | 需 Windows SDK + `php8ts.lib`;资源文件编译 | |
||||
|
||||
Windows 分支会额外 `detectPhpLibs()` 探测 embed 与 core 的 `.lib`,并把 `isZts`、SDK 路径注入 `Windows` 对象。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L170-L181) · [README.md](README.md#L42-L43) |
||||
|
||||
## Windows 资源文件 |
||||
|
||||
`bin` 模式在 Windows 下编译 `.rc`(图标、版本信息、UAC 等,由 `project.yml` 的 `resource` 配置),生成的 `.res` 在 `build()` 链接时并入。资源文件生成见 `Generator/ResourceFileGenerator` 与 `Build/ResourceCompilationTrait`。 |
||||
|
||||
Sources: [project.yml](project.yml#L10-L24) · [src/Translator.php](src/Translator.php#L1653-L1659) · [src/Build/ResourceCompilationTrait.php](src/Build/ResourceCompilationTrait.php) |
||||
|
||||
## libphp.so 自动安装 |
||||
|
||||
Linux 缺 `libphp.so` 时,`tpc.php` 可交互式下载 PHP 源码并自动构建,详见 `docs/LIBPHP_INSTALLER.md`;安装器逻辑在 `src/Installer/`。 |
||||
|
||||
Sources: [README.md](README.md#L27) · [src/Installer/](src/Installer/) |
||||
|
||||
## 相关阅读 |
||||
|
||||
- 后端命令如何生成 → [编译器后端](backend) |
||||
- 链接与资源并入 → [构建流水线](build-pipeline) |
||||
- 二进制打包(UPX/strip) → README 的 Release packaging 段 |
||||
|
||||
</blog> |
||||
@ -0,0 +1,45 @@ |
||||
<!doctype html><html lang="zh"><head><meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width,initial-scale=1"> |
||||
<title>预处理与符号表</title> |
||||
<script src="../script/mermaid.min.js"></script> |
||||
<script>document.addEventListener('DOMContentLoaded',function(){if(window.mermaid)mermaid.initialize({startOnLoad:true});});</script> |
||||
<style> |
||||
:root{--bg:#0f1117;--fg:#e6e6e6;--muted:#9aa0aa;--accent:#6ea8fe;--card:#171a21;--border:#262b36;} |
||||
*{box-sizing:border-box} |
||||
body{margin:0;font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background:var(--bg);color:var(--fg);line-height:1.65} |
||||
.wrap{max-width:900px;margin:0 auto;padding:32px 24px 80px} |
||||
h1,h2,h3{color:#fff;line-height:1.3;margin-top:1.6em} |
||||
h1{border-bottom:1px solid var(--border);padding-bottom:.3em} |
||||
a{color:var(--accent);text-decoration:none} |
||||
a:hover{text-decoration:underline} |
||||
code{background:#0b0d12;padding:.15em .4em;border-radius:4px;font-size:.9em} |
||||
pre{background:#0b0d12;border:1px solid var(--border);border-radius:8px;padding:14px;overflow:auto} |
||||
pre code{background:none;padding:0} |
||||
table{border-collapse:collapse;width:100%;margin:1em 0} |
||||
th,td{border:1px solid var(--border);padding:8px 10px;text-align:left} |
||||
th{background:var(--card)} |
||||
blockquote{border-left:3px solid var(--accent);margin:1em 0;padding:.2em 1em;color:var(--muted);background:var(--card)} |
||||
hr{border:none;border-top:1px solid var(--border);margin:2em 0} |
||||
</style></head> |
||||
<body><div class="wrap"><h1>预处理与符号表</h1> |
||||
<p>在生成任何 C++ 之前,编译器必须先<strong>通读所有 PHP 文件、收集符号、解决依赖顺序</strong>。这一步由 <code>Preprocessor</code>(父类)与 <code>CompilerBase</code>(主体)承担,产物是贯穿全程的全局符号表。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Preprocessor.php">src/Preprocessor.php</a> · <a href="file:///D:\git\php\aot-compiler\src\CompilerBase.php#L97">src/CompilerBase.php</a></p> |
||||
<h2>文件排序</h2> |
||||
<p><code>prepare()</code> 扫描出 PHP 文件后,用 <code>getSortedFiles()</code> 做拓扑排序,保证被依赖的文件先被处理。<code>marcj/topsort</code> 负责依赖排序(Composer 依赖之一)。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Preprocessor.php#L43-L75">src/Preprocessor.php</a> · <a href="file:///D:\git\php\aot-compiler\composer.json#L13">composer.json</a></p> |
||||
<h2>符号收集</h2> |
||||
<p>每个文件经 <code>prepareFile()</code> 解析后,编译器为每个语言构造建立 <code>Entity</code> 定义对象:</p> |
||||
<table><thead><tr><th>实体</th><th>定义类</th><th>收集方法</th></tr></thead><tbody><tr><td>函数</td><td><code>FunctionDef</code></td><td><code>prepareFunction()</code> / <code>parseFunctionDecl()</code></td></tr><tr><td>类 / trait / 枚举</td><td><code>ClassDef</code></td><td><code>prepareClass()</code></td></tr><tr><td>接口</td><td><code>InterfaceDef</code></td><td><code>prepareClass()</code></td></tr><tr><td>属性</td><td><code>PropertyDef</code></td><td><code>addClassProperty()</code></td></tr><tr><td>常量</td><td><code>ConstantDef</code></td><td><code>parseClassLikeConstant()</code> / <code>parseConstDef()</code></td></tr><tr><td>方法</td><td><code>MethodDef</code></td><td><code>parseFunctionDecl()</code></td></tr></tbody></table> |
||||
<p><code>main()</code> 有专门校验:参数必须形如 <code>(int $argc, array $argv)</code> 且返回 <code>void</code>(仅 <code>bin</code> 模式强制要求)。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Preprocessor.php#L489-L589">src/Preprocessor.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Preprocessor.php#L685">src/Preprocessor.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Preprocessor.php#L1124">src/Preprocessor.php</a></p> |
||||
<h2>符号仓库</h2> |
||||
<p>收集到的符号统一存放在 <code>Symbol\SymbolRepository</code>(<code>$this->symbols</code>),按 functions / classes / interfaces 分别索引。<code>genExtension()</code>、各类 <code>genXxx</code> 方法都从仓库读取,保证「声明一次、多处生成」。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Symbol\SymbolRepository.php">src/Symbol/SymbolRepository.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L863-L880">src/Translator.php</a></p> |
||||
<h2>属性默认值计划</h2> |
||||
<p>标量/数组属性默认值会被预处理成 <code>ArrayInitPlan</code>,避免 C++ 初始化时重复求值;数组常量也会被标记 special 处理(见 <a href="pages/generator.html">generator</a> 的属性初始化)。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Preprocessor.php#L974-L1002">src/Preprocessor.php</a></p> |
||||
<h2>数值与常量</h2> |
||||
<p><code>loadInternalConstants()</code> 把 PHP 内置常量(排除用户态、<code>TypePHP</code> 扩展组)载入编译期常量表,供常量折叠使用。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L139-L159">src/Translator.php</a></p> |
||||
<h2>相关阅读</h2> |
||||
<ul><li>解析器如何产出 AST → <a href="pages/parser.html">解析器与 AST</a></li><li>遍历中如何改写节点 → <a href="pages/transform.html">AST 转换</a></li><li>符号如何变成 C++ → <a href="pages/generator.html">代码生成</a></li></ul></div></body></html> |
||||
@ -0,0 +1,56 @@ |
||||
<blog> |
||||
|
||||
# 预处理与符号表 |
||||
|
||||
在生成任何 C++ 之前,编译器必须先**通读所有 PHP 文件、收集符号、解决依赖顺序**。这一步由 `Preprocessor`(父类)与 `CompilerBase`(主体)承担,产物是贯穿全程的全局符号表。 |
||||
|
||||
Sources: [src/Preprocessor.php](src/Preprocessor.php) · [src/CompilerBase.php](src/CompilerBase.php#L97) |
||||
|
||||
## 文件排序 |
||||
|
||||
`prepare()` 扫描出 PHP 文件后,用 `getSortedFiles()` 做拓扑排序,保证被依赖的文件先被处理。`marcj/topsort` 负责依赖排序(Composer 依赖之一)。 |
||||
|
||||
Sources: [src/Preprocessor.php](src/Preprocessor.php#L43-L75) · [composer.json](composer.json#L13) |
||||
|
||||
## 符号收集 |
||||
|
||||
每个文件经 `prepareFile()` 解析后,编译器为每个语言构造建立 `Entity` 定义对象: |
||||
|
||||
| 实体 | 定义类 | 收集方法 | |
||||
|---|---|---| |
||||
| 函数 | `FunctionDef` | `prepareFunction()` / `parseFunctionDecl()` | |
||||
| 类 / trait / 枚举 | `ClassDef` | `prepareClass()` | |
||||
| 接口 | `InterfaceDef` | `prepareClass()` | |
||||
| 属性 | `PropertyDef` | `addClassProperty()` | |
||||
| 常量 | `ConstantDef` | `parseClassLikeConstant()` / `parseConstDef()` | |
||||
| 方法 | `MethodDef` | `parseFunctionDecl()` | |
||||
|
||||
`main()` 有专门校验:参数必须形如 `(int $argc, array $argv)` 且返回 `void`(仅 `bin` 模式强制要求)。 |
||||
|
||||
Sources: [src/Preprocessor.php](src/Preprocessor.php#L489-L589) · [src/Preprocessor.php](src/Preprocessor.php#L685) · [src/Preprocessor.php](src/Preprocessor.php#L1124) |
||||
|
||||
## 符号仓库 |
||||
|
||||
收集到的符号统一存放在 `Symbol\SymbolRepository`(`$this->symbols`),按 functions / classes / interfaces 分别索引。`genExtension()`、各类 `genXxx` 方法都从仓库读取,保证「声明一次、多处生成」。 |
||||
|
||||
Sources: [src/Symbol/SymbolRepository.php](src/Symbol/SymbolRepository.php) · [src/Translator.php](src/Translator.php#L863-L880) |
||||
|
||||
## 属性默认值计划 |
||||
|
||||
标量/数组属性默认值会被预处理成 `ArrayInitPlan`,避免 C++ 初始化时重复求值;数组常量也会被标记 special 处理(见 [generator](generator) 的属性初始化)。 |
||||
|
||||
Sources: [src/Preprocessor.php](src/Preprocessor.php#L974-L1002) |
||||
|
||||
## 数值与常量 |
||||
|
||||
`loadInternalConstants()` 把 PHP 内置常量(排除用户态、`TypePHP` 扩展组)载入编译期常量表,供常量折叠使用。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L139-L159) |
||||
|
||||
## 相关阅读 |
||||
|
||||
- 解析器如何产出 AST → [解析器与 AST](parser) |
||||
- 遍历中如何改写节点 → [AST 转换](transform) |
||||
- 符号如何变成 C++ → [代码生成](generator) |
||||
|
||||
</blog> |
||||
@ -0,0 +1,53 @@ |
||||
<!doctype html><html lang="zh"><head><meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width,initial-scale=1"> |
||||
<title>快速开始</title> |
||||
<script src="../script/mermaid.min.js"></script> |
||||
<script>document.addEventListener('DOMContentLoaded',function(){if(window.mermaid)mermaid.initialize({startOnLoad:true});});</script> |
||||
<style> |
||||
:root{--bg:#0f1117;--fg:#e6e6e6;--muted:#9aa0aa;--accent:#6ea8fe;--card:#171a21;--border:#262b36;} |
||||
*{box-sizing:border-box} |
||||
body{margin:0;font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background:var(--bg);color:var(--fg);line-height:1.65} |
||||
.wrap{max-width:900px;margin:0 auto;padding:32px 24px 80px} |
||||
h1,h2,h3{color:#fff;line-height:1.3;margin-top:1.6em} |
||||
h1{border-bottom:1px solid var(--border);padding-bottom:.3em} |
||||
a{color:var(--accent);text-decoration:none} |
||||
a:hover{text-decoration:underline} |
||||
code{background:#0b0d12;padding:.15em .4em;border-radius:4px;font-size:.9em} |
||||
pre{background:#0b0d12;border:1px solid var(--border);border-radius:8px;padding:14px;overflow:auto} |
||||
pre code{background:none;padding:0} |
||||
table{border-collapse:collapse;width:100%;margin:1em 0} |
||||
th,td{border:1px solid var(--border);padding:8px 10px;text-align:left} |
||||
th{background:var(--card)} |
||||
blockquote{border-left:3px solid var(--accent);margin:1em 0;padding:.2em 1em;color:var(--muted);background:var(--card)} |
||||
hr{border:none;border-top:1px solid var(--border);margin:2em 0} |
||||
</style></head> |
||||
<body><div class="wrap"><h1>快速开始</h1> |
||||
<p>本章给出一个最小可编译示例,以及常用命令。完整的用户手册在独立的 <code>aot/docs</code> 仓库,这里聚焦「能在 5 分钟内跑起来」。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\docs\QUICKSTART.md">docs/QUICKSTART.md</a> · <a href="file:///D:\git\php\aot-compiler\README.md#L7-L26">README.md</a></p> |
||||
<h2>安装依赖</h2> |
||||
<pre><code>composer install # 安装 nikic/php-parser, phpx 等 |
||||
php bin/tpc.php --help # 验证安装</code></pre> |
||||
<p>Linux 还需高精度数学库:<code>sudo apt install libgmp-dev libmpfr-dev libmpdec-dev</code>。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\README.md#L29-L40">README.md</a></p> |
||||
<h2>写一个最小程序</h2> |
||||
<p>可执行代码必须放在 <code>main()</code> 里,类/函数/常量可在全局定义:</p> |
||||
<pre><code><?php |
||||
class Calculator { |
||||
public function add(int $a, int $b): int { return $a + $b; } |
||||
} |
||||
function main(): void { |
||||
$c = new Calculator(); |
||||
echo $c->add(5, 3) . PHP_EOL; |
||||
}</code></pre> |
||||
<p>编译并运行:</p> |
||||
<pre><code>php bin/tpc.php main.php -o myapp |
||||
./myapp # 输出 8</code></pre> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\docs\QUICKSTART.md#L166-L189">docs/QUICKSTART.md</a> · <a href="file:///D:\git\php\aot-compiler\docs\QUICKSTART.md#L99-L127">docs/QUICKSTART.md</a></p> |
||||
<h2>常用命令</h2> |
||||
<table><thead><tr><th>命令</th><th>作用</th></tr></thead><tbody><tr><td><code>php bin/tpc.php hello.php -O2</code></td><td>指定优化级别编译</td></tr><tr><td><code>php bin/tpc.php src/ -o app -j4</code></td><td>目录编译 + 4 路并行</td></tr><tr><td><code>php bin/tpc.php src/ --dry --build-dir /tmp/b</code></td><td>只生成 C++ 不编译(调试用)</td></tr><tr><td><code>php bin/tpc.php app.php -r -O2 -- --flag1 v1</code></td><td>编译后直接运行,并传参</td></tr><tr><td><code>php bin/tpc.php project.yml</code></td><td>用 <code>project.yml</code> 配置编译</td></tr></tbody></table> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L225-L258">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\docs\QUICKSTART.md#L271-L280">docs/QUICKSTART.md</a></p> |
||||
<h2>调试中间产物</h2> |
||||
<p><code>--dry</code> 会把生成的 <code>.cc</code> / <code>_arginfo.h</code> 写入 <code>--build-dir</code> 指定的目录,便于检查翻译结果;<code>--no-progress</code> 则逐文件打印进度。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L30-L36">src/Translator.php</a></p> |
||||
<h2>下一步</h2> |
||||
<ul><li>了解产物形态差异 → <a href="pages/compilation-modes.html">编译模式</a></li><li>理解 <code>project.yml</code> 字段 → 见仓库根 <code>project.yml</code> 与 <code>docs/COMPILER_CLI.md</code></li><li>排查「Not implemented」→ <a href="pages/incompatible-features.html">不支持的 PHP 特性</a></li></ul></div></body></html> |
||||
@ -0,0 +1,68 @@ |
||||
<blog> |
||||
|
||||
# 快速开始 |
||||
|
||||
本章给出一个最小可编译示例,以及常用命令。完整的用户手册在独立的 `aot/docs` 仓库,这里聚焦「能在 5 分钟内跑起来」。 |
||||
|
||||
Sources: [docs/QUICKSTART.md](docs/QUICKSTART.md) · [README.md](README.md#L7-L26) |
||||
|
||||
## 安装依赖 |
||||
|
||||
```bash |
||||
composer install # 安装 nikic/php-parser, phpx 等 |
||||
php bin/tpc.php --help # 验证安装 |
||||
``` |
||||
|
||||
Linux 还需高精度数学库:`sudo apt install libgmp-dev libmpfr-dev libmpdec-dev`。 |
||||
|
||||
Sources: [README.md](README.md#L29-L40) |
||||
|
||||
## 写一个最小程序 |
||||
|
||||
可执行代码必须放在 `main()` 里,类/函数/常量可在全局定义: |
||||
|
||||
```php |
||||
<?php |
||||
class Calculator { |
||||
public function add(int $a, int $b): int { return $a + $b; } |
||||
} |
||||
function main(): void { |
||||
$c = new Calculator(); |
||||
echo $c->add(5, 3) . PHP_EOL; |
||||
} |
||||
``` |
||||
|
||||
编译并运行: |
||||
|
||||
```bash |
||||
php bin/tpc.php main.php -o myapp |
||||
./myapp # 输出 8 |
||||
``` |
||||
|
||||
Sources: [docs/QUICKSTART.md](docs/QUICKSTART.md#L166-L189) · [docs/QUICKSTART.md](docs/QUICKSTART.md#L99-L127) |
||||
|
||||
## 常用命令 |
||||
|
||||
| 命令 | 作用 | |
||||
|---|---| |
||||
| `php bin/tpc.php hello.php -O2` | 指定优化级别编译 | |
||||
| `php bin/tpc.php src/ -o app -j4` | 目录编译 + 4 路并行 | |
||||
| `php bin/tpc.php src/ --dry --build-dir /tmp/b` | 只生成 C++ 不编译(调试用) | |
||||
| `php bin/tpc.php app.php -r -O2 -- --flag1 v1` | 编译后直接运行,并传参 | |
||||
| `php bin/tpc.php project.yml` | 用 `project.yml` 配置编译 | |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L225-L258) · [docs/QUICKSTART.md](docs/QUICKSTART.md#L271-L280) |
||||
|
||||
## 调试中间产物 |
||||
|
||||
`--dry` 会把生成的 `.cc` / `_arginfo.h` 写入 `--build-dir` 指定的目录,便于检查翻译结果;`--no-progress` 则逐文件打印进度。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L30-L36) |
||||
|
||||
## 下一步 |
||||
|
||||
- 了解产物形态差异 → [编译模式](compilation-modes) |
||||
- 理解 `project.yml` 字段 → 见仓库根 `project.yml` 与 `docs/COMPILER_CLI.md` |
||||
- 排查「Not implemented」→ [不支持的 PHP 特性](incompatible-features) |
||||
|
||||
</blog> |
||||
@ -0,0 +1,44 @@ |
||||
<!doctype html><html lang="zh"><head><meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width,initial-scale=1"> |
||||
<title>PHPX 运行时集成</title> |
||||
<script src="../script/mermaid.min.js"></script> |
||||
<script>document.addEventListener('DOMContentLoaded',function(){if(window.mermaid)mermaid.initialize({startOnLoad:true});});</script> |
||||
<style> |
||||
:root{--bg:#0f1117;--fg:#e6e6e6;--muted:#9aa0aa;--accent:#6ea8fe;--card:#171a21;--border:#262b36;} |
||||
*{box-sizing:border-box} |
||||
body{margin:0;font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background:var(--bg);color:var(--fg);line-height:1.65} |
||||
.wrap{max-width:900px;margin:0 auto;padding:32px 24px 80px} |
||||
h1,h2,h3{color:#fff;line-height:1.3;margin-top:1.6em} |
||||
h1{border-bottom:1px solid var(--border);padding-bottom:.3em} |
||||
a{color:var(--accent);text-decoration:none} |
||||
a:hover{text-decoration:underline} |
||||
code{background:#0b0d12;padding:.15em .4em;border-radius:4px;font-size:.9em} |
||||
pre{background:#0b0d12;border:1px solid var(--border);border-radius:8px;padding:14px;overflow:auto} |
||||
pre code{background:none;padding:0} |
||||
table{border-collapse:collapse;width:100%;margin:1em 0} |
||||
th,td{border:1px solid var(--border);padding:8px 10px;text-align:left} |
||||
th{background:var(--card)} |
||||
blockquote{border-left:3px solid var(--accent);margin:1em 0;padding:.2em 1em;color:var(--muted);background:var(--card)} |
||||
hr{border:none;border-top:1px solid var(--border);margin:2em 0} |
||||
</style></head> |
||||
<body><div class="wrap"><h1>PHPX 运行时集成</h1> |
||||
<p>TypePHP 不是从零实现 PHP 语义,而是站在 <strong>PHPX</strong>(Swoole 的 C++ PHP 绑定库)与 <strong>Zend 引擎 embed</strong> 之上。生成的 C++ 大量调用 <code>phpx.h</code> 提供的 <code>php::</code> 命名空间 API,最终把 Zend 引擎链接进产物。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L79-L89">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\README.md#L44-L61">README.md</a></p> |
||||
<h2>全局头文件</h2> |
||||
<p><code>Translator::$globalHeaders</code> 列出每个编译单元默认包含的头:</p> |
||||
<pre><code>['cstring', 'phpx.h', 'phpx_helper.h', 'phpx_big_int.h', |
||||
'phpx_big_float.h', 'phpx_decimal.h', 'typephp_helper.h', |
||||
'typephp_fiber_generator.h', 'phpx_std.h']</code></pre> |
||||
<p>高精度类型(<code>BigInt</code>/<code>BigFloat</code>/<code>Decimal</code>)的头正是此处引入;<code>typephp_*</code> 是 TypePHP 自带的扩展头(Fiber/Generator、helper)。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L79-L89">src/Translator.php</a></p> |
||||
<h2>运行时依赖源</h2> |
||||
<p><code>compile()</code> 会追加 phpx 的 <code>src/misc/</code> 源文件(C++ 运行时实现),以及 embed 模式下的 <code>typephp_main.cc</code>、bin 模式下的 cli 标题源。这些 misc 源受 <a href="pages/incremental-cache.html">增量编译缓存</a> 的 ABI 指纹保护。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L1423-L1434">src/Translator.php</a></p> |
||||
<h2>关键运行时能力</h2> |
||||
<ul><li><strong>Fiber / Generator</strong>:<code>typephp_fiber_generator.cc/.h</code> 提供协程与生成器支持,详见 <code>docs/YIELD_GENERATOR.md</code>;</li><li><strong>混合 C++/PHP</strong>:可在工程中直接写 C++ 并与 PHP 互调,见 <code>docs/MIXED_CPP_PHP.md</code>;</li><li><strong>反射</strong>:<code>typephp_install_reflection_attribute_handlers()</code> 在 MINIT 安装反射/属性处理器;</li><li><strong>类继承</strong>:PHP 类到 C++ 的映射与 <code>extends</code> 处理见 <code>docs/CLASS_INHERITANCE.md</code>。</li></ul> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L887-L890">src/Translator.php</a> · <a href="file:///D:\git\php\aot-compiler\docs\YIELD_GENERATOR.md">docs/YIELD_GENERATOR.md</a> · <a href="file:///D:\git\php\aot-compiler\docs\MIXED_CPP_PHP.md">docs/MIXED_CPP_PHP.md</a> · <a href="file:///D:\git\php\aot-compiler\docs\CLASS_INHERITANCE.md">docs/CLASS_INHERITANCE.md</a></p> |
||||
<h2>动态链接库</h2> |
||||
<p>运行时要求 <code>libphp.so</code>(Linux)/ <code>php8ts.lib</code>(Windows)与 <code>libphpx.so</code> 就位;缺库时可用 <code>docs/LIBPHP_INSTALLER.md</code> 自动构建。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\README.md#L57-L70">README.md</a> · <a href="file:///D:\git\php\aot-compiler\docs\LIBPHP_INSTALLER.md">docs/LIBPHP_INSTALLER.md</a></p> |
||||
<h2>相关阅读</h2> |
||||
<ul><li>产物如何被链接 → <a href="pages/build-pipeline.html">构建流水线</a></li><li>跨平台库差异 → <a href="pages/platform.html">跨平台支持</a></li><li>哪些 PHP 特性尚不支持 → <a href="pages/incompatible-features.html">不支持的 PHP 特性</a></li></ul></div></body></html> |
||||
@ -0,0 +1,50 @@ |
||||
<blog> |
||||
|
||||
# PHPX 运行时集成 |
||||
|
||||
TypePHP 不是从零实现 PHP 语义,而是站在 **PHPX**(Swoole 的 C++ PHP 绑定库)与 **Zend 引擎 embed** 之上。生成的 C++ 大量调用 `phpx.h` 提供的 `php::` 命名空间 API,最终把 Zend 引擎链接进产物。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L79-L89) · [README.md](README.md#L44-L61) |
||||
|
||||
## 全局头文件 |
||||
|
||||
`Translator::$globalHeaders` 列出每个编译单元默认包含的头: |
||||
|
||||
```php |
||||
['cstring', 'phpx.h', 'phpx_helper.h', 'phpx_big_int.h', |
||||
'phpx_big_float.h', 'phpx_decimal.h', 'typephp_helper.h', |
||||
'typephp_fiber_generator.h', 'phpx_std.h'] |
||||
``` |
||||
|
||||
高精度类型(`BigInt`/`BigFloat`/`Decimal`)的头正是此处引入;`typephp_*` 是 TypePHP 自带的扩展头(Fiber/Generator、helper)。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L79-L89) |
||||
|
||||
## 运行时依赖源 |
||||
|
||||
`compile()` 会追加 phpx 的 `src/misc/` 源文件(C++ 运行时实现),以及 embed 模式下的 `typephp_main.cc`、bin 模式下的 cli 标题源。这些 misc 源受 [增量编译缓存](incremental-cache) 的 ABI 指纹保护。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L1423-L1434) |
||||
|
||||
## 关键运行时能力 |
||||
|
||||
- **Fiber / Generator**:`typephp_fiber_generator.cc/.h` 提供协程与生成器支持,详见 `docs/YIELD_GENERATOR.md`; |
||||
- **混合 C++/PHP**:可在工程中直接写 C++ 并与 PHP 互调,见 `docs/MIXED_CPP_PHP.md`; |
||||
- **反射**:`typephp_install_reflection_attribute_handlers()` 在 MINIT 安装反射/属性处理器; |
||||
- **类继承**:PHP 类到 C++ 的映射与 `extends` 处理见 `docs/CLASS_INHERITANCE.md`。 |
||||
|
||||
Sources: [src/Translator.php](src/Translator.php#L887-L890) · [docs/YIELD_GENERATOR.md](docs/YIELD_GENERATOR.md) · [docs/MIXED_CPP_PHP.md](docs/MIXED_CPP_PHP.md) · [docs/CLASS_INHERITANCE.md](docs/CLASS_INHERITANCE.md) |
||||
|
||||
## 动态链接库 |
||||
|
||||
运行时要求 `libphp.so`(Linux)/ `php8ts.lib`(Windows)与 `libphpx.so` 就位;缺库时可用 `docs/LIBPHP_INSTALLER.md` 自动构建。 |
||||
|
||||
Sources: [README.md](README.md#L57-L70) · [docs/LIBPHP_INSTALLER.md](docs/LIBPHP_INSTALLER.md) |
||||
|
||||
## 相关阅读 |
||||
|
||||
- 产物如何被链接 → [构建流水线](build-pipeline) |
||||
- 跨平台库差异 → [跨平台支持](platform) |
||||
- 哪些 PHP 特性尚不支持 → [不支持的 PHP 特性](incompatible-features) |
||||
|
||||
</blog> |
||||
@ -0,0 +1,37 @@ |
||||
<!doctype html><html lang="zh"><head><meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width,initial-scale=1"> |
||||
<title>AST 转换(Lowering)</title> |
||||
<script src="../script/mermaid.min.js"></script> |
||||
<script>document.addEventListener('DOMContentLoaded',function(){if(window.mermaid)mermaid.initialize({startOnLoad:true});});</script> |
||||
<style> |
||||
:root{--bg:#0f1117;--fg:#e6e6e6;--muted:#9aa0aa;--accent:#6ea8fe;--card:#171a21;--border:#262b36;} |
||||
*{box-sizing:border-box} |
||||
body{margin:0;font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background:var(--bg);color:var(--fg);line-height:1.65} |
||||
.wrap{max-width:900px;margin:0 auto;padding:32px 24px 80px} |
||||
h1,h2,h3{color:#fff;line-height:1.3;margin-top:1.6em} |
||||
h1{border-bottom:1px solid var(--border);padding-bottom:.3em} |
||||
a{color:var(--accent);text-decoration:none} |
||||
a:hover{text-decoration:underline} |
||||
code{background:#0b0d12;padding:.15em .4em;border-radius:4px;font-size:.9em} |
||||
pre{background:#0b0d12;border:1px solid var(--border);border-radius:8px;padding:14px;overflow:auto} |
||||
pre code{background:none;padding:0} |
||||
table{border-collapse:collapse;width:100%;margin:1em 0} |
||||
th,td{border:1px solid var(--border);padding:8px 10px;text-align:left} |
||||
th{background:var(--card)} |
||||
blockquote{border-left:3px solid var(--accent);margin:1em 0;padding:.2em 1em;color:var(--muted);background:var(--card)} |
||||
hr{border:none;border-top:1px solid var(--border);margin:2em 0} |
||||
</style></head> |
||||
<body><div class="wrap"><h1>AST 转换(Lowering)</h1> |
||||
<p>在 <code>doConvert()</code> 遍历 AST 时,<code>src/Transform/Visitor.php</code> 作为 <code>NodeVisitor</code> 挂载在遍历链上,对节点做<strong>编译期改写(lowering)</strong>——把 PHP 8.x 的高层语法(属性钩子、构造函数提升、getter、编译期属性等)降级为编译器能直接翻译的普通结构。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Transform\Visitor.php#L19-L36">src/Transform/Visitor.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L2462">src/Translator.php</a></p> |
||||
<h2>两个遍历钩子</h2> |
||||
<p><code>Visitor</code> 实现 <code>enterNode()</code> 与 <code>leaveNode()</code> 两阶段处理:</p> |
||||
<ul><li><strong>enterNode</strong>(进入节点前):校验 + 即时 lowering。依次调用 <code>CompileTimeAttribute::validateNode</code>、<code>FunctionAttributeLowering::lower</code>、<code>GetterLowering::validateTarget</code>、<code>PropertyMethodLowering::validateTarget</code>、<code>ConstructorLowering::validateTarget</code>。</li><li><strong>leaveNode</strong>(离开节点后):对函数/闭包做 <code>ParameterValidationLowering</code>;对类/属性做 <code>PropertyHookLowering</code>、<code>GetterLowering</code>、<code>PropertyMethodLowering</code>,把钩子属性、getter、提升属性改写成方法或标记。</li></ul> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Transform\Visitor.php#L28-L80">src/Transform/Visitor.php</a></p> |
||||
<h2>Lowering 算子清单</h2> |
||||
<table><thead><tr><th>类</th><th>作用</th></tr></thead><tbody><tr><td><code>CompileTimeAttribute</code> / <code>CompileTimeAttributeRegistry</code></td><td>识别并校验编译期属性(如 <code>Any</code>、<code>MustUse</code>)</td></tr><tr><td><code>FunctionAttributeLowering</code></td><td>处理函数上的编译期属性</td></tr><tr><td><code>ConstructorLowering</code></td><td>处理构造函数提升参数</td></tr><tr><td><code>GetterLowering</code></td><td><code>get</code> 钩子属性 → getter 方法</td></tr><tr><td><code>PropertyHookLowering</code></td><td><code>get</code>/<code>set</code> 钩子属性 → 访问器方法</td></tr><tr><td><code>PropertyMethodLowering</code></td><td>属性 ↔ 方法互转</td></tr><tr><td><code>ParameterValidationLowering</code></td><td>参数类型校验,拒绝箭头函数误用</td></tr><tr><td><code>PrinterLowering</code> / <code>ValidateLowering</code></td><td>打印/校验相关降级</td></tr><tr><td><code>ArrayableLowering</code> / <code>NotEmptyLowering</code> / <code>NotNullLowering</code></td><td>特定表达式降级</td></tr><tr><td><code>RuntimeAttributeFactoryLowering</code></td><td>运行时工厂属性(遍历链上独立挂载)</td></tr></tbody></table> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Transform">src/Transform/</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L2467">src/Translator.php</a></p> |
||||
<h2>顺序意义</h2> |
||||
<p>Lowering 必须早于 C++ 生成:例如属性钩子若不先降级成方法,后续 <code>genClassWrapper</code> 就无法生成对应的 C++ 访问逻辑。它处在 <a href="pages/parser.html">解析器与 AST</a> 之后、<a href="pages/generator.html">代码生成</a> 之前。</p> |
||||
<h2>相关阅读</h2> |
||||
<ul><li>编译期属性语义 → <a href="pages/compile-time-attributes.html">编译期属性</a></li><li>降级后如何发射 C++ → <a href="pages/generator.html">生成器总览</a></li><li>常量表达式校验 → <a href="pages/type-check.html">类型检查与兼容</a></li></ul></div></body></html> |
||||
@ -0,0 +1,45 @@ |
||||
<blog> |
||||
|
||||
# AST 转换(Lowering) |
||||
|
||||
在 `doConvert()` 遍历 AST 时,`src/Transform/Visitor.php` 作为 `NodeVisitor` 挂载在遍历链上,对节点做**编译期改写(lowering)**——把 PHP 8.x 的高层语法(属性钩子、构造函数提升、getter、编译期属性等)降级为编译器能直接翻译的普通结构。 |
||||
|
||||
Sources: [src/Transform/Visitor.php](src/Transform/Visitor.php#L19-L36) · [src/Translator.php](src/Translator.php#L2462) |
||||
|
||||
## 两个遍历钩子 |
||||
|
||||
`Visitor` 实现 `enterNode()` 与 `leaveNode()` 两阶段处理: |
||||
|
||||
- **enterNode**(进入节点前):校验 + 即时 lowering。依次调用 `CompileTimeAttribute::validateNode`、`FunctionAttributeLowering::lower`、`GetterLowering::validateTarget`、`PropertyMethodLowering::validateTarget`、`ConstructorLowering::validateTarget`。 |
||||
- **leaveNode**(离开节点后):对函数/闭包做 `ParameterValidationLowering`;对类/属性做 `PropertyHookLowering`、`GetterLowering`、`PropertyMethodLowering`,把钩子属性、getter、提升属性改写成方法或标记。 |
||||
|
||||
Sources: [src/Transform/Visitor.php](src/Transform/Visitor.php#L28-L80) |
||||
|
||||
## Lowering 算子清单 |
||||
|
||||
| 类 | 作用 | |
||||
|---|---| |
||||
| `CompileTimeAttribute` / `CompileTimeAttributeRegistry` | 识别并校验编译期属性(如 `Any`、`MustUse`) | |
||||
| `FunctionAttributeLowering` | 处理函数上的编译期属性 | |
||||
| `ConstructorLowering` | 处理构造函数提升参数 | |
||||
| `GetterLowering` | `get` 钩子属性 → getter 方法 | |
||||
| `PropertyHookLowering` | `get`/`set` 钩子属性 → 访问器方法 | |
||||
| `PropertyMethodLowering` | 属性 ↔ 方法互转 | |
||||
| `ParameterValidationLowering` | 参数类型校验,拒绝箭头函数误用 | |
||||
| `PrinterLowering` / `ValidateLowering` | 打印/校验相关降级 | |
||||
| `ArrayableLowering` / `NotEmptyLowering` / `NotNullLowering` | 特定表达式降级 | |
||||
| `RuntimeAttributeFactoryLowering` | 运行时工厂属性(遍历链上独立挂载) | |
||||
|
||||
Sources: [src/Transform/](src/Transform/) · [src/Translator.php](src/Translator.php#L2467) |
||||
|
||||
## 顺序意义 |
||||
|
||||
Lowering 必须早于 C++ 生成:例如属性钩子若不先降级成方法,后续 `genClassWrapper` 就无法生成对应的 C++ 访问逻辑。它处在 [解析器与 AST](parser) 之后、[代码生成](generator) 之前。 |
||||
|
||||
## 相关阅读 |
||||
|
||||
- 编译期属性语义 → [编译期属性](compile-time-attributes) |
||||
- 降级后如何发射 C++ → [生成器总览](generator) |
||||
- 常量表达式校验 → [类型检查与兼容](type-check) |
||||
|
||||
</blog> |
||||
@ -0,0 +1,38 @@ |
||||
<!doctype html><html lang="zh"><head><meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width,initial-scale=1"> |
||||
<title>类型检查与兼容</title> |
||||
<script src="../script/mermaid.min.js"></script> |
||||
<script>document.addEventListener('DOMContentLoaded',function(){if(window.mermaid)mermaid.initialize({startOnLoad:true});});</script> |
||||
<style> |
||||
:root{--bg:#0f1117;--fg:#e6e6e6;--muted:#9aa0aa;--accent:#6ea8fe;--card:#171a21;--border:#262b36;} |
||||
*{box-sizing:border-box} |
||||
body{margin:0;font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background:var(--bg);color:var(--fg);line-height:1.65} |
||||
.wrap{max-width:900px;margin:0 auto;padding:32px 24px 80px} |
||||
h1,h2,h3{color:#fff;line-height:1.3;margin-top:1.6em} |
||||
h1{border-bottom:1px solid var(--border);padding-bottom:.3em} |
||||
a{color:var(--accent);text-decoration:none} |
||||
a:hover{text-decoration:underline} |
||||
code{background:#0b0d12;padding:.15em .4em;border-radius:4px;font-size:.9em} |
||||
pre{background:#0b0d12;border:1px solid var(--border);border-radius:8px;padding:14px;overflow:auto} |
||||
pre code{background:none;padding:0} |
||||
table{border-collapse:collapse;width:100%;margin:1em 0} |
||||
th,td{border:1px solid var(--border);padding:8px 10px;text-align:left} |
||||
th{background:var(--card)} |
||||
blockquote{border-left:3px solid var(--accent);margin:1em 0;padding:.2em 1em;color:var(--muted);background:var(--card)} |
||||
hr{border:none;border-top:1px solid var(--border);margin:2em 0} |
||||
</style></head> |
||||
<body><div class="wrap"><h1>类型检查与兼容</h1> |
||||
<p>类型检查负责回答两个问题:<strong>「这个值在此处是什么类型?」</strong> 与 <strong>「把 A 赋给期望 B 的槽位是否合法?」</strong>。TypePHP 的类型逻辑集中在 <code>src/TypeSystem/</code> 两个 trait 中,并在遍历/生成阶段被大量调用。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\TypeSystem">src/TypeSystem/</a></p> |
||||
<h2>两个核心 Trait</h2> |
||||
<table><thead><tr><th>Trait</th><th>职责</th></tr></thead><tbody><tr><td><code>NativeTypeCompatibilityTrait</code></td><td>判断原生类型之间的赋值/参数兼容(含子类→基类、可空、协变等规则)</td></tr><tr><td><code>CompositeTypeCheckerTrait</code></td><td>处理联合类型、<code>mixed</code>、交集等复合类型的成员判定</td></tr></tbody></table> |
||||
<p>它们被 <code>CompilerBase</code> 通过 <code>use</code> 引入(与 Parser 各 trait 并列),为 <code>parseParams</code>、<code>genArgumentDeclaration</code> 等生成逻辑提供判定依据。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\CompilerBase.php#L79-L80">src/CompilerBase.php</a></p> |
||||
<h2>检查发生的时机</h2> |
||||
<ol><li><strong>参数解析</strong>:<code>parseParameterType()</code> 决定形参的 C++ 类型;不兼容的默认/传入会在此报错。</li><li><strong>返回值</strong>:函数/方法返回类型在 <code>parseFunctionDecl()</code> 校验,未声明返回类型会 <code>fatalError</code>(要求显式声明)。</li><li><strong>属性赋值</strong>:固定值类型属性赋值受 <a href="pages/native-types.html">native-types</a> 的静态类型规则约束。</li><li><strong>常量表达式</strong>:<code>ConstantExpressionValidationVisitor</code> 在遍历链上校验编译期常量表达式的合法性。</li></ol> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\src\Preprocessor.php#L328-L368">src/Preprocessor.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Preprocessor.php#L497-L536">src/Preprocessor.php</a> · <a href="file:///D:\git\php\aot-compiler\src\Translator.php#L2463-L2466">src/Translator.php</a></p> |
||||
<h2>类型丢失与恢复</h2> |
||||
<p>从数组/函数返回值取出对象时会丢失类型上下文,需用编译期函数 <code>objval($var, 'ClassName')</code> 显式恢复类信息;<code>refval()</code> / <code>any()</code> 等见 <a href="pages/compile-time-attributes.html">编译期属性</a>。</p> |
||||
<p>Sources: <a href="file:///D:\git\php\aot-compiler\docs\NATIVE_TYPES.md#L55-L70">docs/NATIVE_TYPES.md</a></p> |
||||
<h2>相关阅读</h2> |
||||
<ul><li>类型如何映射到 C++ → <a href="pages/native-types.html">原生类型映射</a></li><li>编译期属性如何参与类型推断 → <a href="pages/compile-time-attributes.html">编译期属性</a></li><li>生成时如何消费类型 → <a href="pages/generator.html">生成器总览</a></li></ul></div></body></html> |
||||
@ -0,0 +1,41 @@ |
||||
<blog> |
||||
|
||||
# 类型检查与兼容 |
||||
|
||||
类型检查负责回答两个问题:**「这个值在此处是什么类型?」** 与 **「把 A 赋给期望 B 的槽位是否合法?」**。TypePHP 的类型逻辑集中在 `src/TypeSystem/` 两个 trait 中,并在遍历/生成阶段被大量调用。 |
||||
|
||||
Sources: [src/TypeSystem/](src/TypeSystem/) |
||||
|
||||
## 两个核心 Trait |
||||
|
||||
| Trait | 职责 | |
||||
|---|---| |
||||
| `NativeTypeCompatibilityTrait` | 判断原生类型之间的赋值/参数兼容(含子类→基类、可空、协变等规则) | |
||||
| `CompositeTypeCheckerTrait` | 处理联合类型、`mixed`、交集等复合类型的成员判定 | |
||||
|
||||
它们被 `CompilerBase` 通过 `use` 引入(与 Parser 各 trait 并列),为 `parseParams`、`genArgumentDeclaration` 等生成逻辑提供判定依据。 |
||||
|
||||
Sources: [src/CompilerBase.php](src/CompilerBase.php#L79-L80) |
||||
|
||||
## 检查发生的时机 |
||||
|
||||
1. **参数解析**:`parseParameterType()` 决定形参的 C++ 类型;不兼容的默认/传入会在此报错。 |
||||
2. **返回值**:函数/方法返回类型在 `parseFunctionDecl()` 校验,未声明返回类型会 `fatalError`(要求显式声明)。 |
||||
3. **属性赋值**:固定值类型属性赋值受 [native-types](native-types) 的静态类型规则约束。 |
||||
4. **常量表达式**:`ConstantExpressionValidationVisitor` 在遍历链上校验编译期常量表达式的合法性。 |
||||
|
||||
Sources: [src/Preprocessor.php](src/Preprocessor.php#L328-L368) · [src/Preprocessor.php](src/Preprocessor.php#L497-L536) · [src/Translator.php](src/Translator.php#L2463-L2466) |
||||
|
||||
## 类型丢失与恢复 |
||||
|
||||
从数组/函数返回值取出对象时会丢失类型上下文,需用编译期函数 `objval($var, 'ClassName')` 显式恢复类信息;`refval()` / `any()` 等见 [编译期属性](compile-time-attributes)。 |
||||
|
||||
Sources: [docs/NATIVE_TYPES.md](docs/NATIVE_TYPES.md#L55-L70) |
||||
|
||||
## 相关阅读 |
||||
|
||||
- 类型如何映射到 C++ → [原生类型映射](native-types) |
||||
- 编译期属性如何参与类型推断 → [编译期属性](compile-time-attributes) |
||||
- 生成时如何消费类型 → [生成器总览](generator) |
||||
|
||||
</blog> |
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,76 @@ |
||||
# 2026-08-03 工作日志 |
||||
|
||||
## TypePHP 编译性能分析(docs/COMPILATION_PERFORMANCE_ANALYSIS.md) |
||||
|
||||
**任务**:分析编译实现、提升编译速度、评估 mago 替代 AST 解析。 |
||||
|
||||
**编译管线**(4 阶段): |
||||
1. prepare:扫描+parse(#1)+符号表+拓扑排序(SourcePipelineTrait::prepare → Preprocessor::prepareFile) |
||||
2. convert:parse(#2,重复)+NodeTraverser+生成 C++(Translator::doConvert) |
||||
3. compile:PCH + pcntl 并行(Windows 串行) |
||||
4. build:链接 |
||||
|
||||
**实测瓶颈**(src/ 139 文件,php-parser 5.6.1): |
||||
- 解析吞吐仅 3.18 MB/s,单遍 parse+resolve ≈ 599ms |
||||
- **每个 PHP 文件解析两次**(prepare + convert)→ 纯 PHP 解析 ~1.2s 起步 |
||||
- 生成 .cc 无增量缓存(只有 phpx misc 有),writeFile 无内容比对 → mtime 必变触发全量重编 |
||||
- prepare/convert 串行;Windows 无 pcntl 串行编译 |
||||
- AST serialize 体积膨胀 28.8 倍(47.6MB/1.65MB),unserialize 260ms vs parse+resolve 599ms(快 2.3 倍) |
||||
|
||||
**提速方案**(按 ROI): |
||||
- S1(P0) prepare/convert 合并单次解析(AST 内存/磁盘缓存) |
||||
- S2(P0) 生成 .cc 增量对象缓存 + writeFile 内容比对(key 须含公共声明头) |
||||
- S3(P0) PCH/misc 指纹轻量化(mtime 先行,内容 hash 兜底) |
||||
- S4(P1) 解析阶段 pcntl 并行 |
||||
- S5(P1) Windows 并行(Msvc /MP 或 proc_open) |
||||
- S7(P2) 合并多次 NodeFinder 全树扫描 |
||||
|
||||
**mago 评估结论:不建议替换**。mago 是 Rust 的 PHP 工具链(lint/format/analyze),AST 是 Rust 结构 + CST 模型,与 TypePHP 深度耦合的 php-parser API(296 处引用/75 文件,依赖 NodeTraverser/NameResolver/ConstExprEvaluator/PrettyPrinter/attribute 机制)不兼容。JSON 桥接或 FFI 的成本会吃掉解析速度优势。合理定位:前置语法预检或未来原生前端路线参考。 |
||||
|
||||
**产物**:docs/COMPILATION_PERFORMANCE_ANALYSIS.md(完整报告)、.workbuddy/bench_ast.php(可复现基准脚本) |
||||
|
||||
## 实施 S1+S2(下午追加) |
||||
|
||||
**S1 合并两次解析**: |
||||
- `CompilerBase` 新增 `parseCachedAst()`(按 `$this->file` 缓存原始 AST)+ `cloneAst()`(CloningVisitor 深拷贝) |
||||
- `prepareFile()` 与 `doConvert()` 都改用它 → 每个文件只 parse 一次 |
||||
- 关键约束:`RuntimeAttributeFactoryLowering`/`Visitor` 是有状态 visitor(会向 AST 追加节点),**同一棵 AST 不能二次遍历**,必须返回深拷贝 |
||||
|
||||
**S2 增量缓存**: |
||||
- `writeFile()` 内容比对:相同不覆盖,返回 bool(mtime 稳定,防头文件抖动) |
||||
- 新增 `hasGeneratedObjectFileCache()`:key = sha256(编译命令 + PHP ABI + 生成的 func_decl.h/data_decl.h/_arginfo.h 内容 hash) |
||||
- `isGeneratedSourceFile()`:buildDir 前缀 + .cc 扩展判断 |
||||
- `compileFile()` 对生成的 .cc 走缓存;`save()`/`genExtension()` 仅实际写入时 format |
||||
- 注意:extension-<target>.cc **不应**列入 header 依赖(内容随任何类变化,会让所有 .cc 全量失效) |
||||
|
||||
**实测**(302 文件合成项目,dry,3 次均值): |
||||
- 全量:基线 6011ms → 改动后 5629ms(-6.4%) |
||||
- 增量(不清理 build,第 3 次):5023ms(-16.4% 相对基线冷构建) |
||||
- dry 不含 C++ 编译,S2 完整收益需在 build 场景验证 |
||||
|
||||
**环境/验证要点**: |
||||
- 本机完整编译需要 `PHP_HOME=D:/git/php/tpc_v1095_windows_x86_64`(含 php8embed.lib、SDK/lib/php8ts.lib、phpx/)+ 复制 `tpc_v1095/phpx.dll` 到 `phpx/build/phpx.dll` |
||||
- `tpc_v1095/tpc.exe` 是编译自 `D:\workspace\compiler` 的二进制,本机无法运行(内嵌路径不符) |
||||
- typephp-think(554 文件)补丁后 prepare 通过,convert 阶段 `Cannot re-assign` 是仓库源码类型系统比 v1095 正式版严格(`$str` array→str),非本次改动问题 |
||||
- **git 事故**:git stash 失败损坏 refs(HEAD→speed_build 指向 a92fc0df 对象缺失)。已恢复:分支指向 18decac(可用 commit),onepiece-doudizhu 示例内容在暂存区完好。备份在 `.git-backup-20260803/`,确认后删除 |
||||
|
||||
## git 恢复与提交(下午追加 2) |
||||
|
||||
- **git stash 事故根因确认**:stash 失败不仅丢 refs,还导致 onepiece-doudizhu-win32 全部 19 个文件的 blob 对象缺失(index 引用了不存在的对象)。工作区文件完好。 |
||||
- **恢复方法**:`git reset -- <dir>` 取消暂存 → `git add <dir>`(从工作区重建 blob)→ commit。已恢复为 `449afc1 add onepiece-ddz game example`(4226 行,与原提交同名)。 |
||||
- **S1/S2 已提交**:`ac7813d perf: cache AST across prepare/convert and add generated object cache`(3 文件 +206/-14)。 |
||||
- **最终 git fsck = 0 missing,仓库健康**。 |
||||
- 遗留:`.git-backup-20260803/`(18MB,git 事故备份,确认后删)、`.workbuddy/onepiece-backup/`(文件级备份,可删)。 |
||||
|
||||
## code-wiki 文档生成(2026-08-04) |
||||
|
||||
- 为 aot-compiler 生成了中文 AI Wiki:22 页,7 个章节(概览 / 前端解析 / 类型系统 / 代码生成 / 后端构建 / 优化性能 / 运行时边界)。 |
||||
- **重要修正**:code-wiki skill 的文档写 `<workspace>/.agents/wiki/`,但 `scripts/render.py` 实际读取 `<workspace>/.workbuddy/wiki/`(`wiki_dir = os.path.join(workspace, ".workbuddy", "wiki")`)。写 catalog.xml / pages 必须放 `.workbuddy/wiki/`,否则 render 报 "catalog.xml not found"。 |
||||
- 产物:`D:\git\php\aot-compiler\.workbuddy\wiki/index.html`(左侧目录导航 + 右侧 iframe,离线 Mermaid)。render 命令:`python <skill>/scripts/render.py render <workspace> --lang zh`。 |
||||
|
||||
## 环境结论(重要) |
||||
|
||||
- **本机 MSVC 工具链不完整**:cl.exe + C++ 标准库头存在(`C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/Tools/MSVC/14.44.35207/include/cstring`),但 **Windows SDK(Windows Kits 目录)完全缺失** → 无法完成真实 C++ 编译链接,只能验证到 dry 模式(prepare+convert+生成 .cc)。 |
||||
- `tpc_v1095_windows_x86_64` 是完整 PHP 构建环境:php8embed.lib、SDK/lib/php8ts.lib、phpx/(含 lib/phpx.lib);phpx.dll 需复制到 `phpx/build/phpx.dll` 才能通过校验。 |
||||
- 完整编译需在装有 Windows SDK 的机器执行(用户原编译机)。 |
||||
|
||||
@ -0,0 +1,154 @@ |
||||
# 2026-08-04 |
||||
|
||||
## code-wiki 渲染路径修正 |
||||
|
||||
- 用户将 code-wiki skill 的 render.py 渲染目录从 `.workbuddy/wiki` 改为 `.agents/wiki`。 |
||||
- 实测发现:render.py 的**文档注释**改了,但 `render()`(第243行)与 `browse()`(第328行)函数体仍硬编码 `.workbuddy`。已把这两处改为 `.agents` 并重新渲染成功。 |
||||
- 结论:code-wiki 产物目录现统一为 **`.agents/wiki/`**(catalog.xml 在 `.agents/wiki/data/`,页面 md 在 `.agents/wiki/pages/`)。下次 render 直接 `python render.py render <ws> --lang zh`,无需再复制。 |
||||
- 重新渲染结果:`[done] rendered 22 pages -> .agents/wiki/index.html`。 |
||||
|
||||
## 修复 Windows 资源编译 RC2135 |
||||
|
||||
- 报错:`app_resource.rc(1) : error RC2135 : file not found: by`(资源编译阶段)。 |
||||
- 根因:`src/Build/ResourceCompilationTrait.php` 写 rc 文件时强制加了 UTF-8 BOM(`"\xEF\xBB\xBF" . $rcContent`),而 `src/Generator/ResourceFileGenerator.php` 生成的注释用 `//`。BOM 顶在文件头导致 rc.exe 第1行识别不出 `//` 注释,把 `Generated by TypePHP` 当语句、`by` 当文件名 → RC2135(老版/部分 Windows SDK 的 rc.exe 有此坑)。 |
||||
- 修复:① 去掉 BOM(直接写 `$rcContent`);② 生成内容里的 `//` 注释全改为 `;`(rc 全版本支持的注释符)。中文靠 `#pragma code_page(65001)` 正常处理,无需 BOM。`.h` 头文件里的 `//` 不动(rc 不处理)。 |
||||
- 重要:此修复需**重新编译 tpc.exe** 才生效——当前运行的预编译 `tpc.exe` 每次构建都会按自身逻辑重新生成 rc 文件,改 build/app_resource.rc 不持久。 |
||||
- 临时绕过(不重编也能跑通):把 project.yml 的 `resource:` 整段(第10~24行 icon + version-info)注释掉,`hasResource()` 返回 false,资源编译被跳过,可先验证后续链接;编好带修复的 tpc.exe 后再恢复该段即可重新带图标/版本。 |
||||
- 已应用临时绕过:project.yml 的 `resource:` 整段已改为全注释(带"待带修复的 tpc.exe 重新编译后恢复"标记)。用户可立即重跑 tpc.exe 验证链接链路。 |
||||
|
||||
## LNK1104 链接失败(输出 tpc.exe 被锁) |
||||
|
||||
- 报错:`LINK : fatal error LNK1104: 无法打开文件"tpc.exe"`(乱码是 GBK 被当 UTF-8 解码的"无法打开文件")。 |
||||
- 根因:project.yml `name: tpc` → 输出 `tpc.exe`;`name` 无路径 → `outputDir` 为空,TypePHP 把最终 exe 输出到 cwd 相对路径(`getTargetFileName()` 返回 `'tpc.exe'`,`/OUT:"tpc.exe"`)。用户从编译器自身目录 `D:\git\php\tpc_v1095_windows_x86_64` 启动 tpc.exe(cwd=该目录),于是 `/OUT:"tpc.exe"` 落到正在运行的 `D:\git\php\tpc_v1095_windows_x86_64\tpc.exe` 上,系统拒绝改写正在执行的 exe → LNK1104。 |
||||
- 佐证:无残留 tpc 进程;`build\tpc.exe` 不存在;`build\` 可写;中间产物 rc 在 `tpc_v1095/build/` → cwd 即编译器目录。 |
||||
- 修复:从项目目录 `D:\git\php\aot-compiler` 启动编译器(cd 过去再用绝对路径调 tpc.exe),输出落到 `aot-compiler/tpc.exe`,避开与运行中编译器同名冲突。备选:给 project.yml 换输出名/输出目录(不建议改 `name`,会影响生成符号)。 |
||||
|
||||
## tpc.exe 编译 hello.php 时 OOM(VirtualAlloc 失败) |
||||
|
||||
- 现象:`.\tpc.exe examples/hello.php` 跑到打印第3条 cl 命令(typephp_fiber_generator.cc)后,`VirtualAlloc() failed [0x8 内存资源不足]` x2,随后 `Fatal error: Out of memory (allocated 8388608) (tried to allocate 140736835400432 ≈128TB) in src/compiler.php on line 4`。 |
||||
- 诊断结论:**不是机器内存不够**。实测本机 96GB 物理内存(空闲 74GB)、页面文件空闲 81GB、20 核。`VirtualAlloc` 拒绝是因为请求了一个被算坏的 ~128TB 尺寸(符号扩展/未初始化),OOM 报告把这个坏尺寸打印出来——属症状非根因。 |
||||
- Windows 上 `Platform/Windows::supportsPcntlParallelCompile()` 返回 false(`Windows.php:226`),`Translator.php:1441` 走 `compileSourceFile()` **顺序编译**(`passthru` 逐个跑 cl),**不并行**,`-j` 在此无效。 |
||||
- 隔离测试:`--dry`(仅 prepare+convert 生成 C++)能干净退出(exit 0,不 OOM)→ bug 只在 **compile/build(链接)阶段**。源码 `compiler.php:8` 已 `ini_set('memory_limit','-1')`,且报错走的是 Zend MM "out of system memory" 路径(OS 拒 VirtualAlloc),非撞 memory_limit。 |
||||
- 诡异点:该 tpc.exe 能编译整个 tpc 工程(project.yml)却编不了 151B 的 hello.php → 疑似"单文件 .php→exe"模式的专属 bug(parseArgv 对单文件默认也是 BUILD_MODE_BIN,与 project.yml 同模式,故非 buildMode 差异)。 |
||||
- 待办/建议给用户:① `.\tpc.exe project.yml -O2 -j 8`(从 aot-compiler 目录)确认工程模式仍正常,隔离是否单文件模式专属;② 用 v1095 预编译 `tpc.exe` 跑 `examples/hello.php` 对比,判断是"当前源码回归"还是"v1095 误编译";③ 若需进一步定位,查单文件 build/link 路径里计算分配尺寸的代码(读取文件/字符串长度处)。 |
||||
|
||||
## 确认:崩的是"S1+S2 优化版",v1095 基础版不崩 |
||||
|
||||
- 用户确认:`tpc_v1095`(基础版,未做编译速度优化)编译 `examples/hello.php` **不崩**;刚编出来的 tpc.exe(带 S1+S2:ac7813d)崩 128TB。→ 回归在 S1+S2,或 v1095 误编译了 S1+S2 源码。 |
||||
- S1+S2(ac7813d)只改 3 文件:`CompilerBase.php`/`Preprocessor.php`/`Translator.php`。compile 阶段新增代码**只有** S2 的 generated 缓存:`hasGeneratedObjectFileCache`/`getGeneratedObjectCacheKey`/`getGeneratedHeaderDependencies`/`isGeneratedSourceFile`/`compileFile` 的 `$isGenerated` 分支。 |
||||
- 已逐行审 S2 缓存代码:均读小 metadata、算 sha256、拼字符串,**无直接大块分配**;且前两个 generated 文件(hello.cc/extension-hello.cc)已成功跑过缓存检查+编译(日志里 cl 命令已打印),说明新函数本身能跑。 |
||||
- **S2 设计缺陷(确定要修)**:`getGeneratedHeaderDependencies()` 用 `FilesystemIterator` 扫描整个 `build/include` 收集所有 `*_arginfo.h`。但 `build/include` 被**上一次 tpc 工程编译的残留污染**(含 `php_src_CompilerBase_arginfo.h` 423KB、`php_tpc_func_decl.h`、`php_src_Translator_arginfo.h` 等几十个 tpc 工程头)。后果:① 编译 hello.php 时缓存 key 竟依赖无关 tpc 工程头文件(增量缓存正确性错误);② 每个 generated 单元算 key 都要 `hash_update_file` 这些大残留头,浪费且可能触发异常路径。 |
||||
- **本机 Bash 无法复现**:缺 vcvars/cl 时该 AOT 二进制静默 exit 0 无输出,必须在用户带 VS 环境的命令行里测。 |
||||
- 给用户的两个隔离测试(在 VS 命令行执行): |
||||
- 测试1:`.\tpc.exe examples/hello.php --force`(关掉两套缓存检查)。若通过→缓存路径是触发点。 |
||||
- 测试2(若测试1通过):`rmdir /s /q build` 后 `.\tpc.exe examples/hello.php` 跑两次。若第1次(缓存miss)过、第2次(缓存hit,完整算key并 hash_update_file 污染头)崩→bug 在缓存命中路径的 key 计算;若第1次就崩→在 compile/link 本身(更可能是 v1095 误编译)。 |
||||
- **用户实测测试2:清空 build 后首次(缓存 miss)就崩** → 直接排除"缓存命中路径"(缓存命中路径只在第2次才触发 `hash_update_file` 扫描污染头;首次 `$objectFile` 不存在,`hasGenerated/hasMiscObjectFileCache` 在 1215/1123 行 early-return false,根本走不到 key 计算)。 |
||||
- 进一步逐行审查首次 compile 路径全部可能大分配点: |
||||
- `writeFile` 改返回 bool:7 处调用(gen_stub/ResourceCompilationTrait/Translator 498/663/736/1100/1785)均安全,无副作用。 |
||||
- `parseCachedAst`/`cloneAst`:仅 prepare/convert 用,`--dry` 已验证正常。 |
||||
- `compileFile` 缓存 `if` 块(1354-1360):首次恒 false,benign。 |
||||
- `NativeBuilder::compile()`(31-41):Windows 顺序模式走 `passthru($command,$status)`,**不把 cl 输出累积进数组**,无"读输出撑爆"路径。 |
||||
- `compileSourceFile` 循环(1489-1532):每文件 `compileFile(false)` → miss → `compile()` → passthru 跑 cl → 打印命令。前3个文件成功(cl 命令已打印=status 0),崩在第4个文件进入时。 |
||||
- **最终结论(高置信)**:S1+S2 在首次 compile 路径上没有任何大分配来源,128TB 在 PHP 源码层无出处;而 v1095 基础版编 hello.php 正常、我们的版本崩 → **判定为 v1095 编译器对我们当前源码(含 S1+S2)的误编译(miscompilation)**:v1095 在 AOT 编译改动后的 `Translator.php` 时,把 `compileFile`/编译循环邻近某处 size 符号扩展/算坏(典型 ~2⁴⁷)。`--dry` 不进 compile 循环故不触发。 |
||||
- **决定性验证 = Bootstrap 自举**:用当前 tpc.exe(它编工程成功,编 hello.php 崩)重编 tpc 工程得自举版 tpc.exe-B,再用它编 hello.php。 |
||||
- 通过 → 确认 v1095 误编译,自举换了编译上下文/偏移绕开,后续用自举版做 typephp-think 速度对比即可。 |
||||
- 仍崩 → 源码确有隐藏 bug,需在 `compileFile` 入口加 STDERR 文件名日志 + `NativeBuilder::compile` 前后标记,再编一次精确定位第4个文件及崩因。 |
||||
- 待修(不影响崩溃):`getGeneratedHeaderDependencies()` 通配 `*_arginfo.h` 会纳入 build/include 残留 tpc 工程头(`php_src_*`),应限定为当前 `$this->targetName` 前缀(`str_starts_with($name,'php_'.$targetName.'_') && str_ends_with($name,'_arginfo.h')`)。等自举成功后再单独修并验证,避免重编混入变量。 |
||||
|
||||
## Bootstrap 自举也崩 → 推翻"纯误编译"早期判断 |
||||
|
||||
- 用户实测:`.\tpc.exe project.yml -O2 -j 8`(用我们的 tpc.exe 重编工程,即自举)**同样崩在 typephp_fiber_generator.cc**,与基础版崩溃签名完全一致(2⁴⁷)。 |
||||
- 关键修正:自举崩**不能区分**"v1095 误编译"与"源码真 bug"——因为自举二进制由我们的 tpc.exe(本身可能已被 v1095 误编译)再编一次,缺陷会继承传递。所以自举崩对两种假设都"符合",不是决定性证据。 |
||||
- 进一步精读定位: |
||||
- `getLanguageFromExtension('.cc')` 返回 **null** → misc 文件走 `getCompileCommandOptions()` → 合法 `cl /c` 命令(解释了日志里 misc 文件没抛 RuntimeException,而是正常打印 cl 命令)。 |
||||
- `getMiscObjectCacheKey()` 只做 `hash('sha256', buildCompileFileCommand(...) . "\0" . serialize($abi))`;而 `buildCompileFileCommand`(generated 文件也用)在 generated 路径已验证正常 → **misc 专属 metadata 写入路径不是 2⁴⁷ 来源**。 |
||||
- 仓库真实状态:HEAD=ac7813d(S1+S2);工作树仅我的 RC 修复 + project.yml 注释,无其它碰编译链路的改动。 |
||||
- S1 是前端 AST 缓存(misc 文件不是 PHP,根本不进前端)→ 已排除。S2 是唯一落在 compile 阶段的改动。 |
||||
|
||||
## 二分开关:已禁用 S2 缓存逻辑(compileFile) |
||||
|
||||
- 在 `src/Translator.php` 的 `compileFile()` 里,把 S2 增量对象缓存逻辑**整段去掉**(缓存命中跳过 + `invalidateMisc/GeneratedObjectCache` + `writeMisc/GeneratedObjectCacheMetadata`),退回 S2 之前的纯编译行为。加了 `// [bisect]` 注释标记,定位清楚后删除。 |
||||
- 目的:若用 v1095 重新编译(带此开关的源码)后 `.\tpc.exe examples/hello.php` **不再崩** → 坐实"S2 那段代码被 v1095 AOT 误编译",下一步改写 S2 避开该结构(如去掉 SPL `RecursiveIteratorIterator`、改用更简单 size 计算)。 |
||||
- 若仍崩 → 不是 S2,需扩大范围(revert 全部 S1+S2、或排查 S1+S2 之外的更早提交/phpx 依赖更新 2129145)。 |
||||
- 用户重编命令(必须用 v1095,因为我们的 tpc.exe 也会崩,不能用来重编): |
||||
- 从 `D:\git\php\aot-compiler` 目录:`D:\git\php\tpc_v1095_windows_x86_64\tpc.exe project.yml -O2 -j 8`(RC 修复已在源码、resource 已注释,且无输出冲突 → 可编译+链接成功)。 |
||||
- 再测:`.\tpc.exe examples/hello.php`。 |
||||
|
||||
## 坐实:S2 触发 v1095 误编译 + 已保守化重写 |
||||
|
||||
- 用户实测:用 v1095 重编"二分开关版"(S2 在 compileFile 的调用整段去掉)源码,产出的 `tpc2.exe` 编 `examples/hello.php` **不再崩,成功产出 hello.exe**(7 文件编译+链接全过)。→ **坐实 S2 那段增量对象缓存代码被 v1095 AOT 误编译**(去掉调用即不再触发 2⁴⁷)。S1 已确认安全(--dry 正常)。 |
||||
- 首次编译实际会执行的 S2 高危路径:`writeGeneratedObjectCacheMetadata` → `getGeneratedObjectCacheKey`。该函数原版用了 `hash_init`/`hash_update`/`hash_update_file`/`hash_final` 哈希**资源流**,并调用 `getGeneratedHeaderDependencies()`(含 `FilesystemIterator` SPL 迭代器)。这两类结构在 v1095 AOT 编译下最易被误编译成坏 size(2⁴⁷ 符号扩展)。`hasMiscObjectFileCache` 原版也含 `RecursiveIteratorIterator`/`RecursiveDirectoryIterator`。 |
||||
- **已重写 S2 为保守版**(src/Translator.php),消除全部高危结构: |
||||
1. `getGeneratedObjectCacheKey`:去掉 `hash_init/update/update_file/final` 流,改用 `hash('sha256', implode("\0", $parts))` 单次 + 每个依赖头 `hash_file('sha256', $header)` 单次。 |
||||
2. `getGeneratedHeaderDependencies`:去掉 `FilesystemIterator`,改用 `scandir` 一层遍历;并把 `*_arginfo.h` 通配**限定为当前 target 前缀**(`str_starts_with($name,'php_'.$targetName.'_')`),顺手修了"扫描整个 build/include 含 tpc 工程残留头"的设计缺陷。 |
||||
3. `hasMiscObjectFileCache`:去掉 `RecursiveIteratorIterator`,新增 `collectHeaderFiles()`(scandir 递归,无 SPL 迭代器)替代。 |
||||
4. `getMiscObjectCacheKey` 保持原 `hash('sha256', ...)` 单次调用(已验证安全)。 |
||||
5. 恢复 `compileFile` 里的 S2 调用(缓存命中跳过 + invalidate + writeMetadata),删除二分 `[bisect]` 标记。 |
||||
- 验证:`php -l src/Translator.php` 无语法错误;Grep 确认 Translator.php 内已无 RecursiveIteratorIterator/RecursiveDirectoryIterator/FilesystemIterator/hash_init/hash_update/hash_update_file/hash_final 残留。 |
||||
- **未动的同类结构**:`FileScanner.php`、`Build/PrecompiledHeaderManager.php`、`gen_stub.php` 仍有 SPL 迭代器 + hash 资源流,但**不是本次崩溃元凶**(v1095 编整个工程时这些文件都被正常 AOT 编译且没崩),保持最小改动原则暂不碰。 |
||||
- **下一步验证(用户执行,必须用 v1095 重编,因为我们的 tpc.exe 自己也崩)**: |
||||
``` |
||||
cd /d D:\git\php\aot-compiler |
||||
D:\git\php\tpc_v1095_windows_x86_64\tpc.exe project.yml -O2 -j 8 # 产新 tpc.exe:含保守版S2 + 源码内修复版ResourceFileGenerator(自身无图标,因resource注释) |
||||
rmdir /s /q build |
||||
.\tpc.exe examples\hello.php # 第一次:应不崩出 hello.exe(验证S2修复) |
||||
.\tpc.exe examples\hello.php # 第二次:应命中缓存([cache] skip),更快(验证S2加速) |
||||
``` |
||||
- 若第一次仍崩 → 误编译源不在已改这几处,需更细二分(如逐个恢复 hasMisc/hasGenerated 与 write*Metadata)。 |
||||
- 若两次都过 → S2 修复生效。之后可恢复 project.yml 的 resource 段,用新 tpc.exe 编 project.yml 验证 RC2135 也修好且带图标。 |
||||
|
||||
## 关键反转:保守化重写的 S2 仍崩 128TB → 判定为 v1095 跨函数误编译 |
||||
|
||||
- 用户实测:用 v1095 重编"保守版 S2"(去 SPL 迭代器 + 去 hash 资源流,compileFile 已恢复 S2 调用)源码,产出的 `tpc2.exe` 编 `examples/hello.php` **仍然崩 128TB**,崩溃签名与原始版完全一致(`tried to allocate 140736835400432 ≈2⁴⁷`)。 |
||||
- 这**推翻了"是 SPL 迭代器 / hash 资源流被误编译"的假设**。进一步定位:崩溃发生在**首次编译** `hello.cc`(generated 文件)打印 cl 命令后、进入 `getNativeBuilder()->compile()` 时。首次编译对 `hello.cc` 实际执行的 S2 代码只有 `isPhpxMiscFile()`、`isGeneratedSourceFile()`、`hasGeneratedObjectFileCache()`(obj 不存在→early-return false)、`invalidateGeneratedObjectCache()`;而我新写的保守 `hash()`/`hash_file()` 此时**还没轮到**(它在编译后才写的 metadata 里)。→ 崩点根本到不了哈希,说明它不是某个 helper 的内部写法问题。 |
||||
- **最终判定:v1095 在 AOT 编译 `compileFile` 里那段 S2 包裹代码时,连带把后续 `getNativeBuilder()->compile()` 编坏了**(典型跨函数误编译:A 函数误编→B 函数运行时崩)。窄重写 helper 救不了,因为触发点是"这段 S2 代码被编译/被调用"这件事本身,而不是具体哪行语句。 |
||||
- **这是 v1095 编译器(AOT)的 bug,不是我们源码的逻辑 bug**。在源码层面做局部改写无法可靠规避。 |
||||
- **决策:禁用 S2**(从 `compileFile` 移除全部 S2 调用,退回纯编译态,等同于已证明稳定的 bisect 版),保留 S1(合并两次解析,主要提速点,已确认安全)。S2 的 helper 方法(hasMisc/hasGenerated/getXxxCacheKey/writeXxxMetadata/collectHeaderFiles)作为"死代码"**保留**(已证明:定义但不被 compileFile 调用就安全),待编译器修复后复用。 |
||||
- 当前 `compileFile`(src/Translator.php ~1378)已加注释明确 S2 禁用原因;`php -l` 通过。 |
||||
- **后续可选项(暂不阻塞)**: |
||||
1. 用 v1095 重编当前源码(S1 开、S2 关)→ 应稳定,可正常编 hello.php 与 project.yml。 |
||||
2. 想保留 S2 加速的可试验:用**更低优化级别**(如 `project.yml -O1` 而非 `-O2`)重编 tpc.exe。若 v1095 的误编译是优化级别相关,低级别可能绕开 → 届时再恢复 compileFile 的 S2 调用测试。但 -O1 会让 tpc.exe 自身变慢,需权衡。 |
||||
3. 向 v1095 上游报告该 AOT 误编译(含最小复现:带 S2 包裹的 compileFile → 2⁴⁷ VirtualAlloc)。 |
||||
- 当前 HEAD 仍为 ac7813d 之上的未提交改动(RC2135 修复 + S2 禁用 + resource 段已注释)。待用户验证稳定后,建议提交 S1 部分(已稳定)并将 S2 作为"被编译器 bug 阻塞"的待办保留。 |
||||
|
||||
## typephp-think 编译报 Duplicate class(重复类 fatal) |
||||
|
||||
- 现象:`.\tpc.exe`(S1 开/S2 关的稳定版)编译 `D:\git\php\typephp-think` 时,`Preprocessor->prepareFile` 报 `Duplicate class think\exception\ClassNotFoundException`(首次撞在 `think-container/src/exception/ClassNotFoundException.php`)。 |
||||
- **不是 S1/S2 引入**:`Preprocessor.php:697` 的重复检测 `isset($this->symbolDeclInFile[...])` 是 prepare 阶段的**全局符号表**(第733行赋值、无 resetClass 重置、ac7813d 未动过它)。我们的编译器对跨文件重名类是全局 fatal,比 v1095(别的电脑能编过的预编译版)更严格 → 这正是"别的电脑能编过"的原因(v1095 容忍重复类)。 |
||||
- **根因 = 工程的重名类 + 补丁机制不会解决它们**:`typephp-think` 有 `patches/` 目录镜像 `vendor/`,由 `patch.php`(`copyPatchesSafely()`)在 `composer post-autoload-dump` 时把 `patches/*` **覆盖拷贝**到 `vendor/*` 并写 `.patches_applied`。但 `patches/topthink/` 只含 `framework/think-dumper/think-filesystem/think-orm/think-trace`,**不含 think-container**;覆盖拷贝不会删文件。所以重名类依然存在。用户"今天只更新代码没打补丁"使 vendor 回到未打补丁态(需重跑 `php patch.php`)。 |
||||
- **vendor/ 内真实重名类只有 4 个**(编译器实际会撞的;patches/vendor 成对的不算,因编译器不扫 patches/): |
||||
1. `think\exception\ClassNotFoundException`:framework vs **think-container**(两份字节一致,删 think-container 那份安全)。 |
||||
2. `think\Exception`:framework vs **think-orm/stubs**/Exception.php(stub,删 stub 安全)。 |
||||
3. `think\Facade`:think-container vs **think-orm/stubs**/Facade.php(stub,删 stub 安全)。 |
||||
4. `think\route\Dispatch`:framework 自身两份(`route/Dispatch.php` 规范基类 vs `route/dispatch/Dispatch.php` 命名空间写错成 `think\route`、全工程无引用 `think\route\dispatch\Dispatch` → 死代码,删后者安全)。 |
||||
- **决策:放宽编译器重复检测,而非删 vendor**(为公平对比:v1095 容忍重复类,我们的 tpc.exe 也应如此,避免改输入导致 our-tpc vs v1095 不对等)。改 `Preprocessor.php`: |
||||
- `prepareClass`(~697):重复时 `$this->warning(...)` + `resetClass()` + `return ''`(不再 fatal,保留首个声明)。 |
||||
- `parseInterface`(~1507):重复时 `$this->warning(...)` + `return;`(不再 fatal)。 |
||||
- warning 方法签名 `warning(Node $node, string $msg): void`(CompilerDiagnosticTrait)。`php -l` 通过。 |
||||
- 验证:重编 tpc.exe(v1095)→ 编 typephp-think,应越过该 Duplicate class 继续。若再撞别的重名,说明还有未覆盖的 vendor 内部重复(再扫描确认)。 |
||||
- 备选(不推荐):直接删上述 4 个冗余 vendor 文件。缺点:composer 会还原 + 让我们与 v1095 的输入不一致,破坏速度对比公平性。 |
||||
|
||||
## typephp-think 编译报 Cannot re-assign $str(string→array 类型冲突 fatal) |
||||
|
||||
- 现象:`.\tpc.exe` 编 `typephp-think` 走到 `symfony/var-dumper/Dumper/CliDumper.php:207` 时,`Preprocessor/Translator` 在 convert 阶段 fatal:`Cannot re-assign $str from php::Array to php::Str`。该行是 `dumpString(Cursor $cursor, string $str, bool $bin, int $cut)` 内 `$str = $bin && str_contains($str,"\0") ? [$str] : explode("\n",$str);` —— 形参 `string $str` 先当字符串用,后在 207 行被赋值为数组。 |
||||
- **根因 = 我们的编译器对局部变量/形参做了"单静态类型"假设**:`AssignOpTrait::parseAssignFinally`(~337)对已存在变量调用 `checkVarAssignExpr($left, 现有类型, 新值类型)`;`CompilerBase::checkVarAssignExpr` 对"不兼容"的两次赋值直接 fatal。但 PHP 是动态类型,变量中途换类型是合法的——v1095(别的电脑能编过的预编译版)对此类变量用运行时 variant(`php::Var`)承载,所以不崩。我们之前对 vendor 的容忍(Duplicate class→warning)没覆盖到这种"标量→数组"类型变更。 |
||||
- **关键正确性约束**:不能简单把 fatal 降级为 warning——否则 C++ 里 `php::Str str;` 后面接 `str = <数组>;` 会是类型错误甚至**静默误编译**。正确做法是:被重新赋以不兼容类型的变量,从一开始(声明处)就声明为运行时 variant `php::Var`。 |
||||
- **修复(src 三处)**: |
||||
1. `CompilerBase.php`:新增 `protected array $variantVars = [];`(resetFunction 里清空);新增 `areTypesAssignable($existing,$new): bool`,与 `checkVarAssignExpr` 的兼容规则逐字一致(VAR/REF/同类型/双 native/big 类型 都兼容,其余冲突),仅返回 bool 不 fatal,供预扫描判定。 |
||||
2. `Translator.php`:新增 `computeVariantVars()` + `collectAssignTypes()/collectAssignTypesNode()`(递归走函数体,跳过嵌套 function/closure/arrow,收集每个简单变量赋值 RHS 的 detectTypeOfExpr 类型,并以形参 argInfo->type 作种子);`parseFunction()` 在 SSA 之后调用它,若某变量类型集合存在不兼容对 → 记入 `variantVars`,并把这些形参的 `argInfo->type` 改为 `php::Var`、重拼 `functionDef->params`(用 `genArgumentDeclaration`)。 |
||||
3. `Parser/AssignOpTrait.php`:`parseAssignFinally` 首次声明局部变量时,若 `$var` 在 `variantVars` 中 → `finalVarType = Type::VAR`(声明即 variant),后续赋值走 variant 路径、`checkVarAssignExpr` 因 VAR 提前返回,不再 fatal。 |
||||
- **兼容性**:决策逻辑与旧 `checkVarAssignExpr` 等价——原来能通过的不兼容赋值(int↔float、同类型重复、含 VAR/big)仍不触发;原来会 fatal 的(str↔arr、str↔int 等)现在正确升级为 variant,而非静默误编译。已用独立脚本验证决策矩阵。 |
||||
- **限制**:预扫描只覆盖 `Function_`/`ClassMethod`(走 parseFunction);`Closure`/`ArrowFunction` 走 `parseStmts` 不经过 computeVariantVars,其形参若中途换类型仍可能 fatal(vendor 里少见,遇到再补)。`php -l` 三个文件均通过。 |
||||
- **验证状态**:本机无法端到端重编验证——缺 PHP/Zend 头文件(php.h 不存在),且当前 `PHP_HOME=D:\git\php\tpc_v1092_windows_x86_64`(陈旧残留,非 PHP 安装)导致 `detectPhpLibs` 找不到 php8ts.lib。用户的真实构建环境(含 PHP dev 头 + 正确的 PHP_HOME)在另一台机器,已多次成功重编。须由用户执行重编+重跑验证(见下条命令)。 |
||||
- **用户重编+重跑序列(必须用 v1095,因我们的 tpc.exe 自身也需它编译;S2 已禁用故稳定)**: |
||||
``` |
||||
cd /d D:\git\php\typephp-think && php patch.php |
||||
cd /d D:\git\php\aot-compiler |
||||
set PHP_HOME=<用户正确的 PHP TS dev 安装目录> # 例 D:\Program Files\PhpWebStudy-Data\app\php-8.3.24-ts(且其 dev\php8ts.lib 需在 $phpDir/lib 或 $phpDir 下,必要时拷贝) |
||||
D:\git\php\tpc_v1095_windows_x86_64\tpc.exe project.yml -O2 -j 8 |
||||
rmdir /s /q build |
||||
.\tpc.exe examples\hello.php # 确认自举稳定 |
||||
cd /d D:\git\php\typephp-think |
||||
D:\git\php\aot-compiler\tpc.exe project.yml -O2 -j 8 # 应越过 Duplicate class 与 Cannot re-assign,继续编译 |
||||
``` |
||||
- **注意**:本机实测 `php-8.3.24-ts` 根目录有 `php8embed.lib`、但 `php8ts.lib` 只在 `dev/` 子目录;`detectPhpLibs` 只查 `$phpDir/$phpDir\SDK\lib/$phpDir\lib`,故需把 `dev\php8ts.lib` 拷到 `php-8.3.24-ts\lib\`(或根)才能让 v1095 的 tpc.exe 找到核心库——这是用户环境的常规布局操作。 |
||||
@ -0,0 +1,224 @@ |
||||
# TypePHP 编译实现分析、提速方案与 mago 替代评估 |
||||
|
||||
> 生成日期:2026-08-03 |
||||
> 适用范围:`swoole/typephp` v0.4.3(本仓库 `D:\git\php\aot-compiler`) |
||||
> 说明:所有耗时数字均来自本仓库实际基准测试(`src/` 下 139 个 PHP 文件、约 1.65 MB 源码,PHP 8.4.16 CLI;端到端对比用 302 文件合成项目,Windows + MSVC) |
||||
|
||||
--- |
||||
|
||||
## 0. 实施状态(2026-08-03 更新) |
||||
|
||||
**S1(合并两次解析)与 S2(writeFile 内容比对 + 生成 .cc 增量缓存)已实施并验证。** |
||||
|
||||
### 已落地的改动 |
||||
|
||||
| 文件 | 改动 | |
||||
|---|---| |
||||
| `src/CompilerBase.php` | 新增 `parseCachedAst()` / `cloneAst()`(AST 内存缓存 + CloningVisitor 深拷贝);`writeFile()` 增加内容比对(内容相同不覆盖,返回 bool 保持 mtime 稳定) | |
||||
| `src/Preprocessor.php` | `prepareFile()` 改用 `parseCachedAst()`,消除与 convert 的重复 parse | |
||||
| `src/Translator.php` | `doConvert()` 改用 `parseCachedAst()`;新增 `hasGeneratedObjectFileCache()` / `getGeneratedObjectCacheKey()` / `getGeneratedHeaderDependencies()` / `isGeneratedSourceFile()`;`compileFile()` 对生成的 .cc 走对象缓存;`save()`/`genExtension()` 仅在实际写入时 format | |
||||
|
||||
### 实测收益(302 文件合成项目,dry 模式,3 次取均值) |
||||
|
||||
| 场景 | 基线 | 改动后 | 提升 | |
||||
|---|---|---|---| |
||||
| 全量构建(冷) | 6011 ms | 5629 ms | **-6.4%** | |
||||
| 增量构建(第 3 次,不清理 build) | — | 5023 ms | **-16.4%**(相对基线冷构建) | |
||||
|
||||
说明:dry 模式不包含 C++ 编译,S2 对象缓存的更大收益(跳过 g++/cl 编译)需在完整 build 场景体现;dry 耗时中固定开销(CLI 启动、YAML、符号表)占比高,稀释了 S1 的解析节省。 |
||||
|
||||
### 验证记录 |
||||
|
||||
- `parseCachedAst`:同一文件 prepare+convert 各调用一次,第二次命中缓存且返回深拷贝(不共享节点、无 resolvedName 残留污染)✓ |
||||
- `writeFile` 内容比对:相同内容跳过写入,mtime 保持不变 ✓ |
||||
- `isGeneratedSourceFile`:buildDir 前缀 + .cc 扩展名判断,与 `getCppFile` 路径一致 ✓ |
||||
- PHPUnit:Entity 目录 85 测试、FileScanner 等 110 测试通过(1 个 Windows 路径分隔符既有失败与本次无关) |
||||
- `typephp-think`(554 文件):补丁后 prepare 通过,convert 阶段因「仓库源码类型系统比 v1095 正式版严格」(`Cannot re-assign`)受阻,属源码版本差异,非本次改动问题 |
||||
|
||||
--- |
||||
|
||||
## 1. 编译是如何实现的(管线剖析) |
||||
|
||||
### 1.1 总体流程 |
||||
|
||||
入口为 `bin/tpc.php` → `src/compiler.php` 的 `main()` → `src/Translator.php`(继承 `Preprocessor` → `CompilerBase`)。编译是一条四阶段流水线: |
||||
|
||||
``` |
||||
┌────────────────────────────────────────────────────────────────────────┐ |
||||
│ ① prepare() 扫描+解析+建符号表+依赖拓扑排序 │ |
||||
│ src/Build/SourcePipelineTrait.php::prepare() │ |
||||
│ → 每文件: Preprocessor::prepareFile() │ |
||||
│ parser->parse() ←── AST 解析 #1 │ |
||||
│ NodeTraverser(NameResolver + Visitor + 常量校验 + AttributeLower) │ |
||||
│ 收集 symbolDeclInFile / symbolCallInFile / classMap / funcMap │ |
||||
│ → getSortedFiles(): marcj/topsort 按文件间符号依赖拓扑排序 │ |
||||
├────────────────────────────────────────────────────────────────────────┤ |
||||
│ ② convert() 每文件: AST → C++ 源码 │ |
||||
│ src/Build/SourcePipelineTrait.php::convert() │ |
||||
│ → Translator::convertFile() → doConvert() │ |
||||
│ loadFile() 读盘(第二次) │ |
||||
│ parser->parse() ←── AST 解析 #2(同一文件解析两次!) │ |
||||
│ NodeTraverser 再次遍历(与 prepare 相同的 4 个 visitor) │ |
||||
│ 逐节点翻译生成 C++(CompilerBase 4000 行核心逻辑) │ |
||||
│ → 生成 func_decl.h / data_decl.h / extension-<target>.cc │ |
||||
├────────────────────────────────────────────────────────────────────────┤ |
||||
│ ③ compile() C++ → .o(外部编译器) │ |
||||
│ Translator::compile() │ |
||||
│ → phpx misc 文件 + 生成的 .cc │ |
||||
│ → PCH 预编译头(PrecompiledHeaderManager,内容指纹缓存) │ |
||||
│ → Linux/macOS: pcntl fork 并行(默认 4 jobs,大文件优先调度) │ |
||||
│ → Windows: 串行(supportsPcntlParallelCompile() = false) │ |
||||
│ → phpx misc 有 .o 缓存(hasMiscObjectFileCache,命令+ABI 指纹) │ |
||||
├────────────────────────────────────────────────────────────────────────┤ |
||||
│ ④ build() 链接为可执行文件 / 扩展 / 库 │ |
||||
│ Translator::build() → NativeBuilder::link() │ |
||||
└────────────────────────────────────────────────────────────────────────┘ |
||||
``` |
||||
|
||||
### 1.2 关键实现位置 |
||||
|
||||
| 职责 | 文件 | |
||||
|---|---| |
||||
| 四阶段编排 | `src/Build/SourcePipelineTrait.php`(prepare/convert)、`src/Translator.php`(compile/build) | |
||||
| PHP→C++ 逐节点翻译 | `src/CompilerBase.php`(4133 行,核心) | |
||||
| 扫描/符号表/依赖排序 | `src/Preprocessor.php` | |
||||
| 编译器抽象 | `src/Backend/`(CompilerBackend → GccLikeBackend → Gcc/Clang、Msvc) | |
||||
| 平台抽象 | `src/Platform/`(Linux/Macos/Windows) | |
||||
| 并行编译调度 | `src/Build/NativeBuilder.php::dispatchParallel()` + `SourceCompileQueue` | |
||||
| PCH 管理 | `src/Build/PrecompiledHeaderManager.php` | |
||||
| 生成物落盘 | `CompilerBase::writeFile()`(无内容比对,直接覆盖) | |
||||
|
||||
### 1.3 当前已具备的优化 |
||||
|
||||
1. **PCH 预编译头**:`phpx.h` 等 8 个公共头打成 `.gch`,带 24 位 sha256 内容指纹缓存(`PrecompiledHeaderManager`)。 |
||||
2. **phpx misc 对象缓存**:`phpx/src/misc/*.cc` 的 `.o` 用「编译命令 + PHP ABI」指纹缓存,避免每次全量重编 PHPX 运行时。 |
||||
3. **编译并行**:Linux/macOS 用 pcntl fork 并行(`-j`,默认 4),且按「大文件优先占满槽位 + 小文件快速通道」调度。 |
||||
4. **编译期常量展开、字面量字符串表**、`--dry` 只生成 C++ 等。 |
||||
|
||||
--- |
||||
|
||||
## 2. 性能瓶颈实测 |
||||
|
||||
### 2.1 基准方法 |
||||
|
||||
用 `nikic/php-parser 5.6.1`(与仓库 `composer.json` 一致)对 `src/` 全部 139 个 PHP 文件(约 1.65 MB)做多轮测量: |
||||
|
||||
``` |
||||
parse (nikic/php-parser) ×3 1455.5 ms → 单遍 ≈ 485 ms(3.18 MB/s) |
||||
parse + NameResolver ×3 1797.0 ms → 单遍 ≈ 599 ms |
||||
parse+resolve+serialize (1x) 701.1 ms |
||||
unserialize ×3 779.8 ms → 单遍 ≈ 260 ms |
||||
parse+resolve+prettyPrint ×3 2196.0 ms |
||||
serialized AST 体积 47.6 MB(源码的 28.8 倍) |
||||
``` |
||||
|
||||
### 2.2 结论性瓶颈清单(按影响排序) |
||||
|
||||
| # | 瓶颈 | 证据 | 影响 | |
||||
|---|---|---|---| |
||||
| B1 | **每个 PHP 文件被解析两次** | `prepareFile()`(Preprocessor.php:130)与 `doConvert()`(Translator.php:2325)各自 `parser->parse()` 一次,且各自跑一遍完整 NodeTraverser | PHP 侧最大浪费:139 文件规模下纯解析+resolve ≈ 2×599ms ≈ **1.2s 起步**,大项目线性放大 | |
||||
| B2 | **生成的 .cc 无增量缓存** | `compileFile()` 只对 phpx misc 走 `hasMiscObjectFileCache`;用户代码生成的 `.cc` 每次全量重编 | 改 1 个 PHP 文件也要重编全部 .cc(C++ 编译是耗时的绝对大头) | |
||||
| B3 | **生成文件无内容比对** | `CompilerBase::writeFile()` 直接 `file_put_contents` 覆盖,mtime 必然变化 | 即使内容相同也触发下游重新依赖判断/重编,破坏增量可能性 | |
||||
| B4 | **prepare/convert 阶段完全串行** | 两阶段都是单进程 `foreach` | 多核只用于 compile;PHP 侧解析/翻译占用的核数为 1 | |
||||
| B5 | **Windows 无并行编译** | `Windows::supportsPcntlParallelCompile() = false`,直接走 `compileSourceFile()` 串行 | Windows 大项目编译时间 = 串行全量 | |
||||
| B6 | **PCH/缓存指纹每次全量计算** | `PrecompiledHeaderManager::buildFingerprint()` 每次构建都递归遍历 phpx 头文件并逐个 hash(实测 131 个头文件 ≈ 42ms,PHP 侧还有 misc 缓存同样的遍历) | 每次构建的固定开销,虽不大但在累积 | |
||||
| B7 | 转换阶段反复 `getType()` 字符串比较、NodeFinder 多次全树扫描(如 `findSymbolUsing`、`canOptimizeMultiReturn`) | CompilerBase/Preprocessor 中多次独立 `findInstanceOf` | 每文件多次 O(N) 全树扫描,可合并为一次遍历 | |
||||
|
||||
### 2.3 一个反直觉的事实 |
||||
|
||||
**AST 序列化缓存是划算的**:unserialize 单遍 260ms vs parse+resolve 599ms(快 2.3 倍),即使加上 serialize 成本(首轮 ~700ms/139 文件),二次构建纯 PHP 解析阶段也能从 ~1.2s 降到 ~260ms。但注意序列化体积膨胀 28.8 倍(47.6MB/1.65MB),对磁盘 I/O 有压力——更优做法是**合并两阶段解析**(见方案 S1)。 |
||||
|
||||
--- |
||||
|
||||
## 3. 提速方案(按性价比排序) |
||||
|
||||
### S1(P0)prepare/convert 合并为单次解析 —— 省一半 PHP 解析时间 |
||||
|
||||
- **问题**:同一文件 `prepare` 和 `convert` 各 parse+traverse 一次,逻辑完全重复(visitor 列表一致)。 |
||||
- **做法**:让 `prepareFile()` 把 parse 好的 `$stmts`(NameResolver 等已跑完)挂到文件缓存(内存 `array<string, array<Node>>`,或按 `filemtime+内容hash` 落盘 `build/cache/ast/`),`doConvert()` 优先取缓存;取不到(如 `--force`、跨进程)才重新 parse。 |
||||
- **收益**:139 文件规模 PHP 解析从 ~1.2s → ~0.6s;大项目直接减半。 |
||||
- **风险**:低。`convert` 依赖的 `resolvedName` 等 attribute 由 NameResolver 在 traverse 时写入,缓存的是 traverse 之后的 AST,语义不变。需注意 `ConstantExpressionValidationVisitor` 的报错回调在 prepare 是 warning、convert 是 fatal,缓存后错误在 prepare 阶段就能暴露,行为只会更早更一致。 |
||||
|
||||
### S2(P0)生成 .cc 的增量对象缓存 —— 编译期最大收益 |
||||
|
||||
- **做法**:把 `hasMiscObjectFileCache()` 的机制推广到所有生成的 `.cc`:缓存 key = 编译命令 + PHP ABI + **生成物内容 hash(或源 PHP hash + 编译器版本)**。内容未变 → 跳过 g++/clang。 |
||||
- **配套**:`writeFile()` 加「内容比对,相同则不落盘」逻辑(解决 B3),保证 mtime 稳定。 |
||||
- **收益**:改 1 个文件后二次构建,C++ 编译从全量变为仅差异文件;这是肉眼可感知的最大提升。 |
||||
- **风险**:中。生成 .cc 的内容由 `genFunctionDeclarations`/`genDataDeclarations` 等公共头影响——若公共头变了,所有 .cc 的 `#include` 语义可能变,但 .cc 内容 hash 不会变。**必须把公共声明头也纳入 key**(hash func_decl.h/data_decl.h/extension 文件内容),或采用「.cc 内容未变 且 公共头未变 且 .o 存在 且 命令指纹未变」四条件跳过。 |
||||
|
||||
### S3(P0)修复 PCH/缓存指纹的计算时机 |
||||
|
||||
- `buildFingerprint()` 每次构建全量扫描+hash 头文件(~42ms + misc 缓存同款遍历),应改为「mtime+size 列表指纹」先行判断,内容 hash 仅在前者变化时执行。 |
||||
|
||||
### S4(P1)prepare/convert 并行化 |
||||
|
||||
- parse+resolve 是纯函数,可用 pcntl fork 分片解析(子进程只做 parse+serialize,父进程归并反序列化),类似已有 `dispatchParallel` 的模式。转换阶段因共享状态(literalStrings、classMap 等)风险高,可先只并行「解析」,翻译仍串行。 |
||||
|
||||
### S5(P1)Windows 并行编译 |
||||
|
||||
- 两条路:(a) 给 `Msvc` 后端加 `/MP`(MSVC 原生多进程编译,单命令即可);(b) Windows 上用 `proc_open` 实现多进程调度替代 pcntl。收益对 Windows 用户显著。 |
||||
|
||||
### S6(P2)工具链层 |
||||
|
||||
- `ccache`/`sccache` 兜底(对 C++ 编译做内容缓存,配合 S2 效果更稳);链接器换 `mold`/`lld`;`-pipe`、`-fno-asynchronous-unwind-tables` 等编译 flag 微调。 |
||||
|
||||
### S7(P2)单次遍历替代多次 NodeFinder |
||||
|
||||
- `findSymbolUsing()` 等每文件多次 `findInstanceOf` 全树扫描,可合并为一次 visit 收集函数调用/类引用/常量引用三类符号,减少 O(N) 重复。 |
||||
|
||||
--- |
||||
|
||||
## 4. AST 解析能否用 mago 替代?—— 结论:不建议(现阶段不可行) |
||||
|
||||
### 4.1 mago 是什么 |
||||
|
||||
[mago](https://github.com/carthage-software/mago)(carthage-software/mago)是一个 **Rust 编写的 PHP 工具链**:lint、format、静态分析(对标 Clippy/OXC),v1.45.0(2026-07),MIT/Apache-2.0 双许可,开发活跃。其核心是自研高性能 PHP 解析器(crate:`mago-syntax` 词法/语法/遍历、`mago-names` 名称解析),官方基准:7M 行 WordPress 静态分析 1.46s(PHPStan 55.9s)、lint 0.88s、format 0.43s。**已支持 PHP 8.4 property hooks、asymmetric visibility(private(set) 等)。** |
||||
|
||||
### 4.2 为什么不能直接替代 |
||||
|
||||
| 维度 | nikic/php-parser(现状) | mago | 兼容性判断 | |
||||
|---|---|---|---| |
||||
| 语言/进程 | PHP 类库,进程内对象 | Rust 二进制/crate,AST 是 Rust 结构 | 无法在 PHP 进程中直接消费 | |
||||
| AST 模型 | AST(抽象语法树),含 attribute 机制(`resolvedName`/`namespacedName` 等存于节点属性) | CST(具体语法树,含 trivia),`mago ast --json` 是调试输出 | 结构不同,需要完整映射层 | |
||||
| 下游依赖 | TypePHP 全库 296 处 `PhpParser\*` 引用、75 个文件;依赖 `NodeTraverser`/`NodeVisitor`/`NameResolver`/`NodeFinder`/`ConstExprEvaluator`/`PrettyPrinter`/`Modifiers` 等 | 无 PHP API | 替换 = 重写编译器前端 | |
||||
| 名称解析 | `NameResolver` 写入节点 attribute,后续代码生成大量读取 | `mago-names` 输出到 Rust 侧 | 需要桥接层搬运 | |
||||
| 代码生成 | `PrettyPrinter` 用于 stub 生成(`LibraryImportStubGenerator`、`gen_stub.php`) | 无等价物 | 缺失 | |
||||
| 错误语义 | `PhpParser\Error` + 行列号,被 `SyntaxError` 包装 | 错误模型不同 | 需要适配 | |
||||
|
||||
**核心矛盾**:TypePHP 不是「解析完就丢」的 linter,而是「AST 必须留在 PHP 进程内、被 4000 行 CompilerBase 逐节点翻译」的编译器。走 mago 只有两条路,都不可行: |
||||
|
||||
1. **mago CLI → JSON AST → PHP 重建对象**:JSON 序列化体积远大于源码(参考第 2 节:php-parser AST 序列化已膨胀 28.8 倍,mago CST 只多不少),反序列化 + 对象重建的 CPU/内存开销会**吃掉**解析省下的时间,且每文件一次进程启动(exec)成本极高;同时丢失 attribute 机制、注释/行列语义需重新映射。 |
||||
2. **PHP FFI 绑定 mago-syntax crate**:需要为整个 Rust AST 写 FFI 边界 + 转 PHP 对象层,工程量接近重写前端,且 mago 的 CST 与 TypePHP 需要的「带 resolvedName 的 AST」不是一回事,仍要在 PHP 侧自建名称解析与代码生成数据模型。 |
||||
|
||||
### 4.3 mago 在本项目中的合理定位(可选) |
||||
|
||||
- **前置快速语法校验**:编译前用 `mago`(或 `mago lint --quick`)做廉价的全项目语法/明显错误预检,给出比 php-parser 更快的反馈(适合 IDE/CI 场景,不进入编译流水线核心)。 |
||||
- **性能参照物**:mago 证明了「Rust 原生解析」的量级(~百 MB/s vs php-parser 3 MB/s),可作为未来「把前端重写为原生编译器(如 Rust 侧做 parse+name-resolution,产物是自研序列化 AST)」的路线参考——但那是一个全新项目,而非对现有编译器的增量改造。 |
||||
- **若仍想引入原生解析**:更现实的是保留 php-parser 语义、仅加速解析环节(如 `--php-parser` 的 `PhpParser\ParserFactory` 换用 tree-sitter 绑定并在 PHP 侧重建 php-parser 节点),但收益-成本比仍不如 S1/S2。 |
||||
|
||||
### 4.4 结论 |
||||
|
||||
> **不建议用 mago 替换 nikic/php-parser**。mago 是「解析即弃」的工具链,TypePHP 是「解析后深度消费 AST」的编译器,二者 AST 模型与进程模型不兼容,桥接成本会抹平解析速度优势。 |
||||
> 真正的提速路径在 **S1(两阶段合并单次解析)+ S2(生成 .cc 增量缓存 + writeFile 内容比对)+ S4/S5(并行化)**,全部基于现有架构增量改造,风险可控、收益立竿见影。 |
||||
|
||||
--- |
||||
|
||||
## 5. 落地顺序建议 |
||||
|
||||
``` |
||||
第一阶段(P0,改动小收益大,1-2 天) |
||||
1. writeFile 内容比对(S2 前置) |
||||
2. prepare/convert 共享 AST(S1) |
||||
3. 生成 .cc 增量对象缓存(S2,key 含公共头内容 hash) |
||||
第二阶段(P1,结构性收益) |
||||
4. PCH/misc 指纹轻量化(S3) |
||||
5. 解析阶段 pcntl 并行(S4 解析部分) |
||||
6. Windows 并行(/MP 或 proc_open)(S5) |
||||
第三阶段(P2,长期) |
||||
7. 单次遍历合并 NodeFinder(S7) |
||||
8. ccache / mold / lld(S6) |
||||
``` |
||||
|
||||
## 6. 附:基准脚本 |
||||
|
||||
分析所用基准脚本:`.workbuddy/bench_ast.php`(可重复运行:`php .workbuddy/bench_ast.php`),复现本节所有数字。 |
||||
Loading…
Reference in new issue