# PHP

«bold»能写一般程序«/»的子集：`<?php … ?>` 标签（标签外按 HTML 原样输出，«bold»没有任何开标签«/»时整份文件当 PHP）、`$变量`、`echo` / `print`、完整算术 / 比较 / 逻辑 / 位运算、`if` / `while` / `do-while` / `for` / `foreach` / `switch`、函数（含默认参数、递归、`global`）、下标数组（`[]` 与 `array()` 两种字面量）。

「完整运算 + 控制流 + 函数调用」三件都齐。

## 在手机上怎么跑

```
vml run examples/php/fib.php
```

编译要等一会儿（C 那种要一两分钟，脚本类语言几秒）。程序跑起来后**屏幕底部就是手柄**，
方向键 + 四个动作键都在；点右上角返回可以回到命令行。

## 写法要点

- `ui_*` «bold»直接写«/»就行（其余一切名字都按名字发 `CALL`，链接期由前缀表把对应的 `.vml` 拉进来）
- `echo` 可以一次给多个参数（无分隔连着打）；字符串拼接是 `.`
- 数组字面量 `[10, 20, 30]` 与 `array(10, 20, 30)` 等价；`$a[] = v` 是«bold»追加«/»
- `require` / `include` 在本前端是«bold»声明«/»（无操作），删掉照样编得过
- 变量（`$name`）与关键字«bold»大小写不敏感«/»；注释有 `//` `#` `/* */` 三种

## 示例

| 文件 | 演示什么 |
|---|---|
| `fib.php` | 斐波那契（递归 + 迭代 + 数组） |
| `hello.php` | 最小程序（`echo` + 字符串拼接 + 算术） |
| `sort.php` | 冒泡排序（数组读写 + 嵌套循环 + 交换） |

## 实测踩过的坑

- ⚠ «bold»关联数组 `["k" => 1]` 不支持«/»，而且«bold»编译期报错«/»（不静默丢键）；对象 / 类 / 接口 / 闭包 / 匿名函数 / `try`-`catch` / `isset` / `unset` / `empty` / `goto` 也都不支持。
- ⚠ «bold»数组元素不带类型«/»：`echo $arr[i]` 一律走«bold»整数«/»通道 ⇒ 字符串元素打出来是«bold»指针值«/»（用例 `24-knownred-elemfmt.php` 钉着这条）。
- ⚠ «bold»字符串与数字的隐式拼接不转换«/»：`"x" . 5` 得 `"x"`（不是 `"x5"`）—— 运行期那一格分不出「整数」与「串指针」，硬转反而更错。
- ⚠ «bold»`switch` 每个 case 自动 `break`«/»（不支持落穿）；case 的值«bold»必须是编译期整数常量«/»（字符串 case / 范围 case 编译期报错）。
- ⚠ 用户函数的«bold»浮点形参 / 返回值按整数传«/»（先 `D2I` 截断）—— 浮点只在«bold»顶层«/»与«bold»内置函数之间«/»完整可用，跨用户函数会丢小数。
- 未定义变量«bold»按 0 处理«/»（不报 `Undefined variable`，与真 PHP 有意不同）；`break 2;` / `continue 2;` 的«bold»层数被忽略«/»（按 1 处理）。

---

下面的内容是**从 VML 源码里直接带的**（`third_party/vml/VMLPrepares/PhpCompiler/`）：
`README` 讲这个前端支持什么、怎么编；`语言规范` 讲语法本身。
上游一改，这里重新生成就是最新的。

## 语言规范

### PHP 语言子集规格（都来码 / Dolaima）

适用：`VMLPrepares/PhpCompiler`。«bold»判据的唯一出处«/»是 `scripts/vml-php-probe/run.sh`
（当前 «bold»通过 25 / 失败 0 / 已知红 1«/»）—— 本文里凡是写"支持"的，那条都有一条能红的用例；
写"不支持"的，多数有一条 `EXPECT-ERR` 用例钉着。

---

> «bold»版本«/»：v1.0 | «bold»日期«/»：2026-10-13 | «bold»修订者«/»：深圳市探索智能科技有限公司

#### 规范标准

| 字段 | 值 |
|:-----|:----|
| «bold»目标标准«/» | PHP 5/7 子集 |
| «bold»发布年份«/» | 2004 |
| «bold»完成度«/» | 子集（未逐项统计） |
| «bold»测试«/» | 25 通过 / 0 失败 / 1 已知红 |

#### 关键字

`if` `elseif` `else` `endif` `while` `endwhile` `do` `for` `endfor` `foreach`
`endforeach` `as` `switch` `endswitch` `case` `default` `break` `continue`
`return` `function` `global` `echo` `print` `true` `false` `null` `nil` `and`
`or` `xor` `not` `array`

#### 概述
支持 PHP 5/7 子集，编译为 VML 汇编代码。既支持 `<?php … ?>` 段与 HTML 混排（`?>` 之后的内容按 HTML 原样输出；«bold»没有任何开标签«/»时整份文件当 PHP），也支持纯 PHP 文件；值是«bold»静态分档«/»的：每个值在编译期归到 `Int`（32 位 / 4 字节）或 `Float`（双精度），`/` 一律双精度、其余算术任一侧是浮点就走双精度。内置函数专用发射，其余一切名字一律发 `CALL <原名>`、由链接期的 `SharedPrefixMap` 按前缀拉库（`ui_` → `vmlui`、`tty_` → `tty`…），库里没有这个名字是«bold»链接期报错«/»、不静默；`require` / `include` 只是«bold»声明«/»、不加载任何东西。与其它前端有一处«bold»有意不同«/»：不跑预处理器（PHP 里 `#` 是注释符）。

#### 支持的语言特性

本前端接受的语言特性按下方原有章节组织，每节都写明「收什么写法、是什么语义」：

- «bold»文件与标签«/»：`<?php … ?>` / `<?= … ?>` / 没有开标签时整份当 PHP —— §一
- «bold»词法«/»：变量 `$name`、注释（`//`、`#`、`/* */`）、数字、单 / 双引号字符串与插值、标识符（关键字大小写不敏感） —— §二
- «bold»语句«/»：`echo` / `print`、赋值与复合赋值、下标读写与 `[]` 追加、`if` / `elseif` / `else`（`{ }` 与 `: … endif;` 两套）、`while` / `do…while`、`for`、`foreach`、`switch`、`break` / `continue`、`function` / `return`、`global`、`require` / `include`、HTML 段 —— §三
- «bold»表达式与运算«/»：优先级表、算术、比较（含 `===`）、逻辑两套、位运算、`.` 拼接、三元与 `?:` / `??`、自增自减 —— §四
- «bold»类型档位«/»：`Int` / `Float` 的判定规则与 `echo` 的分流 —— §五
- «bold»内置函数«/»：`strlen` / `count` / `strtoupper` / `strtolower` / `substr` / `strpos` / `implode` / `explode` / `intval` / `floatval` / `abs` / `max` / `min` / `rand` / `sprintf` / `printf` / `array_push` / `array_pop` / `intdiv` 等 —— §六
- «bold»数组«/»：`[元素个数, e0, e1, …]` 布局与指针语义 —— §七
- «bold»不支持项«/»：关联数组、对象与类、闭包、`try` / `catch`、`isset` / `unset` / `empty`、`goto` 等（多数«bold»响亮报错«/»） —— §八
- «bold»已知差异«/»：能跑、但与真 PHP 不同的 10 条 —— §九

详见下方各节。

#### 一、文件与标签

| 写法 | 行为 |
|---|---|
| `<?php … ?>` | PHP 段执行；`?>` 之后的内容按 «bold»HTML 原样输出«/»，且 `?>` 会吃掉紧跟的一个换行 |
| `<?= 表达式 ?>` | 等价于 `<?php echo 表达式 ?>` |
| «bold»没有任何开标签«/» | «bold»整份文件当 PHP«/»（本仓例程的主用法） |

判据：`cases/17-tagmode.php`。

> 「有没有开标签」是«bold»文本级«/»预判（找 `<?php` / `<?=`）。若你在源代码的字符串字面量里
> 写 `"<?php"`，会被当成开标签 —— 已记档的取舍，别指望它。

#### 二、词法

* «bold»变量«/»：`$name`（`[A-Za-z_][A-Za-z0-9_]*`）。«bold»未赋值就读«/»不报错，按 0 处理（子集行为，
  与 PHP 的 `Warning: Undefined variable` 有意不同）。
* «bold»注释«/»：`// …`、`# …`、`/* … */`（«bold»不嵌套«/»）。
* «bold»数字«/»：十进制、`0x` 十六进制、小数、`1e3`。全部按 «bold»32 位整数«/» 存；只有出现在需要浮点的
  场合（见第五节）才走双精度。
* «bold»字符串«/»：
  * 单引号 `'…'`：«bold»只«/»认 `\\` 与 `\'`，其余原样（PHP 语义）。
  * 双引号 `"…"`：认 `\n \t \r \0 \\ \" \$`；`$var` 会«bold»插值«/»（`\$` 是不插值的字面美元号）。
* «bold»标识符«/»：裸名（函数名）。关键字«bold»大小写不敏感«/»。

#### 三、语句

| 语句 | 备注 |
|---|---|
| `echo e1, e2, …;` / `print e;` | 无分隔符；`print` 按语句处理（不返回 1） |
| `$x = 值;` `$x op= 值;` | `op` ∈ `+ - * / % .`；复合赋值等价于 `$x = $x op 值` |
| `$a[i] = 值;` `$a[] = 值;` | `[]` 是«bold»追加«/» |
| `if / elseif / else` | 两套写法都支持：`{ }` 与 `: … endif;` |
| `while` `do…while` | 也支持 `: … endwhile;` |
| `for (init; cond; step)` | `cond` 里用 `,` 分隔会被当成 `&&` |
| `foreach ($a as $v)` / `as $k => $v` | «bold»只对下标数组«/»（键是 0-based 整数） |
| `switch / case / default` | «bold»case 值必须是编译期整数常量«/»；«bold»每个 case 自动 break«/»（见「已知差异」） |
| `break;` `continue;` | `break 2;` 这种«bold»层数被忽略«/»（按 1 处理） |
| `function f($a, $b = 默认值) { … }` `return 值;` | 递归可用；默认值在«bold»调用点«/»就地求值补位 |
| `global $a, $b;` | 之后函数体里的 `$a`/`$b` 指向顶层（全局）变量 |
| `require/include[_once] '文件';` | «bold»声明«/»，无操作（库函数按名字解析，见第六节） |
| HTML 段 | 等价于一条 `echo "原文";` |

#### 四、表达式与运算

«bold»优先级从低到高«/»（同 PHP 大体一致）：`or` → `xor` → `and` → 赋值（右结合）→
`?:` / `??` → `||` → `&&` → `|` → `^` → `&` → 相等 → 关系 → 移位 → `+ - .` → `* / %` →
一元 `! - + ~ ++ --` → `**`（右结合）→ 后缀 `[] ++ --` 与调用。

* 算术：`+ - * / % «bold»`。`«/»` 走共享 `ipow`（«bold»整数幂«/»）。
* 比较：`== != === !== < <= > >= <>`。`===` / `!==` 与 `==` / `!=` «bold»同义«/»（没有类型标签可分）。
* 逻辑：`&& || !` 与 `and or not xor`（两套都是«bold»短路«/»并归一成 0/1）。
* 位运算：`& | ^ ~ << >>`。
* 字符串拼接：`.`（见「已知差异」）。
* 三元：`a ? b : c` 与简写 `a ?: c`；`??` 按「左为 0/空则取右」实现。
* 自增自减：前缀与后缀都支持（后缀返回«bold»旧值«/»）。

#### 五、类型档位（决定发什么指令）

本前端是«bold»静态分档«/»的：每个值在编译期归到 `Int`（32 位通用寄存器 / 4 字节栈槽）或
`Float`（`D0` / 8 字节栈槽）。

* 字面量：带小数点或指数 ⇒ `Float`，否则 `Int`。
* «bold»`/` 一律双精度«/»（PHP 语义：`17/25` 得 `0.68`，不是 `0`）。
* 其余算术：«bold»任一侧是 `Float` 就走双精度«/»（`ADDD`/`SUBD`/`MULD`/`DIVD`）。
* 字符串与数组本质是«bold»指针«/»，走 4 字节。
* «bold»`echo` 的分流«/»：`String` → `print_str`；`Float` → `print_float`（先 `D2F`）；
  其余 → `print_int`。

> ⚠ «bold»与 `Lib/` 的调用约定对齐«/»：整数保持 32 位/4 字节 —— 全按双精度会«bold»当场对不上«/»
> 库的 4 字节形参区（Lua 前端当初就踩过这条，这里沿用同一结论）。

#### 六、内置函数

«bold»专用发射«/»（前端自己排版实参）：

| 函数 | 底层 | 说明 |
|---|---|---|
| `strlen($s)` | `CALL strlen` | |
| `count($a)` / `sizeof($a)` | 读 `[base]` | 数组长度（`[len, e0, …]` 布局） |
| `strtoupper($s)` / `strtolower($s)` | `alloc` + `str_toupper`/`str_tolower` | 返回«bold»新串«/» |
| `substr($s, $start[, $len])` | `alloc` + `str_substr` | `$len` 省略 = 到末尾 |
| `strpos($h, $n)` | 单字符字面量 → `str_indexof`；否则 `strstr` − 基址 | 找不到回 `-1` |
| `implode($sep, $arr)` | `join_str` | ⚠ «bold»只对整数元素«/»（库的实现是把元素当整数转十进制串） |
| `explode($sep, $s)` | `str_split` + 本前端数组布局 | 分隔符取 `$sep` 的«bold»首字符«/» |
| `intval` / `floatval` | 就地转换 | |
| `abs` / `max` / `min` | `CALL abs/max/min` | «bold»整数«/»版；`max`/`min` 支持多参（折叠成两两调用） |
| `rand()` / `rand($min, $max)` | `random` / `random_range` | |
| `sprintf($fmt, …)` | `printf2`…`printf5` / `sprintf` | 值个数 0–5 |
| `printf($fmt, …)` | 同上 + `print_str` | |
| `array_push($a, $v)` | 就地追加 | 数组字面量已留 64 字节余量 |
| `array_pop($a)` | 弹末尾 | 空数组回 0 |
| `intdiv($a, $b)` | `DIV` | |
| `print_r` / `var_dump` | 按 `echo` 处理 | 子集简化 |
| `require` / `include` 家族 | 无操作 | 但 `require` 可«bold»不带括号«/»收裸表达式 |

«bold»其余一切按名字直接 `CALL`«/»：`ui_2d_clear(...)` → `CALL ui_2d_clear`，
链接期由 `SharedPrefixMap` 的 `ui_` → `vmlui`（`tty_` → tty、`str` → string …）拉库。
库里没有这个名字 ⇒ «bold»链接期«/»报 `未定义的函数 'x'（引用 N 次）`，«bold»不会静默«/»。

#### 七、数组

布局与 `Lib/shared/array.c` «bold»同源«/»：`[元素个数, e0, e1, …]`，每格 4 字节。
数组名本身是«bold»指针«/»（4 字节），所以能当参数传、能 `return`。

```php
$a = [10, 20, 30];      // 等价于 array(10, 20, 30)
echo $a[1], "\n";       // 20
$a[2] = 3;              // 按下标写
$a[] = 30;              // 追加（长度 +1）
echo count($a);         // 4
```

#### 八、不支持项（«bold»有意不做«/»，多数会«bold»响亮报错«/»）

| 项 | 现状 |
|---|---|
| «bold»关联数组«/» `["k" => 1]` | «bold»编译期报错«/»「关联数组（`键 => 值`）暂不支持」——«bold»不静默丢键«/» |
| `{$expr}` 插值、`$a[i]` 插值 | 不支持；双引号串里只认 `$名字` |
| 对象 / 类 / 接口 / trait | 不支持 |
| 闭包 / 匿名函数 / `use` | 不支持 |
| `try` / `catch` / `throw` | 不支持 |
| `switch` 的字符串 case、范围 case | «bold»编译期报错«/»（只收编译期整数常量） |
| 用户函数的 «bold»浮点«/»形参 / 返回值 | 按«bold»整数«/»传递（先 `D2I`）—— 见「已知差异」 |
| `isset` / `unset` / `empty` / `list` / `die` / `exit` | 不支持 |
| `include_path` / 命名空间 / 自动加载 | 不支持（库按名字解析） |
| `goto` | 不支持 |

#### 九、已知差异（能跑，但与真 PHP 不同 —— 一条条列出来）

1. «bold»数组元素不带类型«/»：`echo $arr[i]` 一律走«bold»整数«/»通道 ⇒ 字符串元素打出来是«bold»指针值«/»。
   用例 `cases/24-knownred-elemfmt.php` 标 `KNOWN-RED` 钉着这条。
2. «bold»字符串与数字的隐式拼接不转换«/»：`"x" . 5` 得 `"x"`（不是 `"x5"`）——
   运行期那一格分不出"整数"与"串指针"，硬转反而更错。
3. «bold»`switch` 每个 case 自动 `break`«/»：«bold»不支持落穿«/»（fallthrough）。写了 `break;` 也无害。
4. «bold»用户函数跨边界按整数«/»：浮点实参先 `D2I`（截断），返回值同理。
   ⇒ 浮点在«bold»顶层«/»与«bold»内置函数之间«/»完整可用，跨用户函数会丢小数。
5. «bold»`break 2;` / `continue 2;`«/» 的层数被忽略。
6. «bold»`$a[i]++` 之类«/»会«bold»求值下标两次«/»（有副作用的表达式会有差异）。
7. «bold»未定义变量«/»按 0（不报 `Undefined variable`）。
8. «bold»`echo` 一个数组«/»打的是指针值。
9. «bold»`implode` 只处理整数元素«/»（库的 `join_str` 如此）。
10. «bold»`print` 不返回 1«/»（当语句处理）。

#### 十、判据

```bash
scripts/vml-php-probe/run.sh          # 通过 25 / 失败 0 / 已知红 1
```

«bold»走的是真实通道«/»：每个用例都由 `vmlcli <case.php> --lang php` 一条命令
「编译 → 汇编 → 链接（含 `Lib/php` 模块集）→ 运行」。
（早先"自己调 `PhpCompiler.dll` 出 `.vmb`、再喂给 vmlcli"的写法**绕开了前端注册表与
`Lib/<lang>/` 的解析**，把三类缺陷一次性盖住了 —— 见 `bugs/vml_php_bugs/README.md` 的 PHP-BUG-06。）

两条«bold»能红«/»的回归判据（改坏了立刻红，都实测过）：

* `cases/23-ctrlflow-vmb.php` —— 把 `CodeGenerator.PlaceLbl` 改回 `AddLabel`
  （标签发 `LABEL` 伪指令），`.vmb` 的符号表整体错位 ⇒ «bold»期望 `6 30` / 实得空输出«/»。
* `cases/03-strings.php` —— 把拼接缓冲尺寸里的 `len(a)` 丢掉 ⇒
  «bold»实得一大串 `ababab…`«/»（堆块重叠、自我复制）。

平台级缺陷的完整记录（现象 / 根因 / 测量 / 规避）见
[`bugs/vml_php_bugs/README.md`](../../../bugs/vml_php_bugs/README.md)。

## 编译器 README

### PHP 编译器（`VMLPrepares/PhpCompiler`）

«bold»路径«/»：`third_party/vml/VMLPrepares/PhpCompiler/`
«bold»扩展名«/»：`.php`
«bold»标准库«/»：`Lib/php/`（`builtin.vml` = 库聚合器；`vml_ui.php` = 文档级声明表）
«bold»判据«/»：`scripts/vml-php-probe/run.sh`（«bold»真实通道«/»：`vmlcli <case> --lang php`）—— 实测 «bold»通过 25 / 失败 0 / 已知红 1«/»
«bold»语言子集与差异«/»：[`PHP_LANGUAGE_SPEC.md`](PHP_LANGUAGE_SPEC.md)（[EN](PHP_LANGUAGE_SPEC.en.md)）
«bold»接线«/»：[`INTEGRATION.md`](INTEGRATION.md)（本次按约定不动共享文件）

#### 是什么

一个«bold»能写一般程序«/»的 PHP 子集前端：`<?php … ?>` 标签（标签外按 HTML 原样输出）、
`$变量`、`echo`/`print`、完整算术/比较/逻辑/位运算、`if/elseif/else`（含 `endif` 备用语法）、
`while` / `do-while` / `for` / `foreach`（含 `as $k => $v`）、`switch`、`break`/`continue`、
函数（含默认参数、递归、`global`）、下标数组（`[]` 与 `array()` 两种字面量）、
单/双引号字符串（双引号支持 `$var` 插值）、`//` `#` `/* */` 注释，
以及一批内置函数（见 spec）。

«bold»「完整运算 + 控制流 + 函数调用」三件都齐«/» —— `Examples/php/` 里的三个例程可跑
（含递归、数组传参与返回、冒泡排序）。

#### 怎么跑

«bold»接线已完成«/»（见 `INTEGRATION.md`），所以走的是«bold»真实通道«/» —— 与手机端 `MauiVml` 等价的
「编译 → 汇编 → 链接（含 `Lib/php` 模块集）→ 运行」：

```bash
dotnet build scripts/vmlcli/vmlcli.csproj -c Release
export VML_HOME=$PWD/third_party/vml

# ① 编 + 跑（一条命令）
dotnet scripts/vmlcli/bin/Release/net10.0/vmlcli.dll third_party/vml/Examples/php/hello.php --lang php

# ② 只看前端产出的汇编（不链接、不跑）
dotnet third_party/vml/VMLPrepares/PhpCompiler/bin/Release/net10.0/PhpCompiler.dll        third_party/vml/Examples/php/hello.php -o /tmp/hello.vml

# ③ 语言特性套件
scripts/vml-php-probe/run.sh
```

> ⚠ «bold»判据必须从真实通道进«/»（这一条是踩过坑的）：上一版套件是"自己调 `PhpCompiler.dll`
> 编成 `.vmb`、再 `vmlcli <vmb>`"。那条路«bold»绕开了前端注册表与 `Lib/<lang>/` 的解析«/»，
> 于是「`vmlcli` 没注册 php」「`vmltool.config.xml` 缺 php 行」「`Libs=` 缺 `array.vml`」
> 这类缺陷«bold»一条都照不出来«/»（自己拼的链接集恰好补齐了缺的模块）。
> 细节见 [`bugs/vml_php_bugs/`](../../../bugs/vml_php_bugs/README.md) 的 PHP-BUG-06。

#### 库函数怎么来

两条路，«bold»都不是靠"读声明文件"«/»：

1. «bold»内置表«/»（`CodeGenerator.Builtins.cs`）：`strlen` / `count` / `substr` / `strtoupper` /
   `strtolower` / `strpos` / `implode` / `explode` / `intval` / `floatval` / `abs` / `max` /
   `min` / `rand` / `sprintf` / `printf` / `array_push` / `array_pop` / `intdiv` /
   `print_r` / `var_dump` / `require` 家族。
   这些要前端自己排版实参（字符串要 dst 缓冲、数组要按 `[len, e0, …]` 走），所以不走名字解析。
2. «bold»按名字直接发 `CALL`«/»：其余一切（`ui_2d_clear` / `tty_puts` / 任何库导出名）。
   链接期由 `CompilerHelper` 的 `SharedPrefixMap`（`ui_` → `vmlui`、`str` → `string` …）
   把对应 `.vml` 拉进来 —— 与 Lua / Ruby / Python 那几门«bold»同一条口径«/»。

`require 'vml_ui.php';` 是«bold»声明«/»（本前端把 `require`/`include` 当无操作语句）：
«bold»删掉它程序照样编得过、跑得对«/»（`LoadKind = 文档级`，见 `docs/UI库导入约定.md`）。
`Lib/php/vml_ui.php` 因此是«bold»给人看的«/»注释表。

#### 与其它前端的«bold»一处有意不同«/»：不跑预处理器

`CompilerHelper.CompileFileStandard` 在源码出现 `#` 时起预处理器，而 «bold»PHP 里 `#` 是注释符«/»
—— 两者在天上打架。⇒ PHP 有意«bold»绕开那个模板«/»：只有源码里真出现 `#include` 时才起预处理器。

#### 目录

```
PhpCompiler/
├── TokenType.cs / Token.cs        词法单元（Token 实现 ITokenPosition，位置由基类一处取）
├── Lexer.cs                       继承 LexerBase；`<?php ?>` 段切分、双引号串插值与 `\$` 占位
├── ASTNode.cs                     节点（自带行/列）
├── Parser.cs                      继承 ParserBase；优先级爬升 + 备用语法（`endif`/`endwhile`…）
├── CodeGenerator.cs               类型档位表 + 符号表/作用域 + 帧槽（PlaceLbl 是本前端的硬约束）
├── CodeGenerator.Expressions.cs   表达式（含字符串拼接、下标读写、短路逻辑、三元）
├── CodeGenerator.Statements.cs    语句（含 foreach/switch/函数定义/默认参数补位）
├── CodeGenerator.Builtins.cs      内置函数专用发射
├── PhpCompiler.cs / PhpPlugin.cs  静态入口 / 插件（继承 CompilerPluginExBase）
├── Program.cs                     开发期 CLI（`--vmb` / `-o` / `--info` / `--dump`）
├── PhpCompiler.csproj
├── README.md / README.en.md
└── PHP_LANGUAGE_SPEC.md / PHP_LANGUAGE_SPEC.en.md
```

#### 已知缺陷 / 限制

见 [`bugs/vml_php_bugs/`](../../../bugs/vml_php_bugs/README.md)（平台级 2 条 + 前端自己的错 2 条 + 限制 2 条），
以及 spec 的「不支持项」。«bold»最重要的一条平台级缺陷«/»：`.vmb` 的符号表会被 `LABEL` 伪指令
«bold»整体偏移一格«/» —— 本前端靠「标签只登记、不发伪指令」规避，且有一条«bold»能红«/»的回归判据
（`scripts/vml-php-probe/cases/23-ctrlflow-vmb.php`）。
