TypePHP 编译器 https://swoole.com/aot/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

3.9 KiB

TypePHP 兼容性工程准则

TypePHP 的目标是保证常规应用代码正确、类型安全、稳定且高效,而不是复刻 ZendVM 每一个可观察的边缘行为。当 PHP 的精确兼容性与 PHPX 封装性、长期 可维护性或静态编译模型冲突时,应优先保护架构,并明确记录行为差异。

优先级

优先级 必须处理的范围 示例
P0 崩溃、UAF、内存破坏、生命周期错误、生成非法 C++、静默破坏数据 Cache 域混淆、对象生命周期错误、特定后端崩溃
P1 常用语法产生明显错误结果、类型检查被绕过、普通副作用表达式被重复求值 ArrayAccess 赋值错误写入 offsetGet() 临时值;receiver 被执行两次
P2 依赖动态引用、回调、警告或废弃转换的低频组合 操作期间由回调把 array 改成 object;警告产生顺序
非目标 只为低频兼容细节而镜像 ZendVM 内部实现 向 PHPX 复制大量 zend_execute.czend_vm_def.h 代码

P0 和 P1 必须修复。P2 只有在方案足够小、通用且符合现有架构时才修复; 否则应归类为 Partial、Intentional Rule 或 Hard Limit。

架构边界

  • 不向 PHPX 复制大段 ZendVM executor 逻辑。
  • 不为单个编译器边缘场景增加 PHPX 公共 API。
  • 不向生成的项目代码暴露 zval *、HashTable slot 等 Zend 存储细节。
  • 新 PHPX API 必须表达通用操作,符合现有命名和所有权模型,并且不只服务于 某一个 PHPT 复现代码。
  • 只有编译器能够证明安全时,才生成原生快速路径。
  • 与其引入庞大的动态兼容层,更应选择清晰的 TypePHP 专有规则或诊断。
  • 静态阶段能够确定的非法操作应在编译期失败。只能在运行期确定的非法操作 可以抛出稳定、统一的 PHPX 错误,不承诺错误级别、文本和时序与 Zend 完全一致。

Code Review 决策流程

接受兼容性修改前,应依次回答:

  1. 问题是否会导致崩溃、内存或数据破坏、非法 C++、类型规则穿透,或者破坏 常用语法?
  2. 编译器能否证明所需的派发方式和求值顺序?
  3. 是否能够使用现有 TypePHP/PHPX 抽象完成修复?
  4. 如果需要新增 API,它是否具有独立、通用的价值,并位于正确的层次?
  5. 实现是否能够跨受支持的 PHP 版本长期工作,而不需要跟踪 ZendVM 私有代码?

如果第一项是否定的,而后续问题显示实现复杂度与收益明显不成比例,应记录 兼容边界,而不是继续实现。

数组维度赋值案例

对于 $container[$key] ??= $value,需要保证的主要行为是:

  • 确定为数组时写入真实 bucket;
  • 确定为 ArrayAccess 对象时,在正确分支调用 offsetExists()offsetGet()offsetSet()
  • 普通 receiver、key 和 RHS 表达式不会被无故重复执行;
  • 不能把 offsetGet() 返回的临时值当成对象维度写入目标。

这些属于常用路径的正确性。相比之下,回调在各阶段之间重新绑定 container/key、 false 转数组的废弃警告、字符串 offset 的全部返回值细节,以及警告的精确顺序, 属于边缘兼容问题。不能因此让 PHPX 复制 ZendVM 的维度处置逻辑。

TypePHP 明确将 null 数组 key 视为追加。除非经过单独的设计决策,否则必须保留 这一既有不兼容行为。

文档与测试

  • 有意或部分不兼容行为必须写入 INCOMPATIBLE_PHP_FEATURES.md,必要时同时在 PHP_INCOMPATIBILITY_CLASSIFICATION.md 中分类。
  • 回归测试应保护项目承诺支持的边界,不应强制尚未承诺的 Zend 边缘行为。
  • 除非诊断文本已经成为稳定的 TypePHP 契约,否则测试不应锁死完整报错文本。
  • 仅缺少测试通常可以在可靠实现合入后补齐,但不能为了满足测试接受错误的架构。