docs: define compatibility engineering policy

master
韩天峰 15 hours ago
parent e90d6246ec
commit e4d8cbb798
  1. 84
      docs/en/COMPATIBILITY_POLICY.md
  2. 7
      docs/en/INCOMPATIBLE_PHP_FEATURES.md
  3. 3
      docs/en/PHP_INCOMPATIBILITY_CLASSIFICATION.md
  4. 1
      docs/en/README.md
  5. 68
      docs/zh-cn/COMPATIBILITY_POLICY.md
  6. 5
      docs/zh-cn/INCOMPATIBLE_PHP_FEATURES.md
  7. 1
      docs/zh-cn/README.md

@ -0,0 +1,84 @@
# TypePHP Compatibility Engineering Policy
TypePHP aims to make ordinary application code correct, type-safe, stable and
fast. It does not attempt to reproduce every observable ZendVM edge case. When
exact PHP compatibility conflicts with PHPX encapsulation, maintainability or
static compilation, the architecture takes precedence and the difference must
be documented.
## Priority
| Priority | Required work | Examples |
|---|---|---|
| P0 | Crashes, use-after-free, memory corruption, lifecycle bugs, invalid generated C++, and silent data corruption | Cache-domain confusion, invalid object lifetime, backend-specific crashes |
| P1 | Clearly wrong results in common language constructs, bypassed type checks, or repeated evaluation of ordinary side-effecting expressions | `ArrayAccess` assignment writing to an `offsetGet()` temporary; evaluating a receiver twice |
| P2 | Uncommon combinations whose exact behavior depends on dynamic aliases, callbacks, warnings, or deprecated conversions | A callback rebinding an array to an object during an operation; exact warning order |
| Non-goal | Mirroring ZendVM internals solely for obscure compatibility | Copying large parts of `zend_execute.c` or `zend_vm_def.h` into PHPX |
P0 and P1 issues must be fixed. P2 behavior is fixed only when the solution is
small, general, and consistent with the existing architecture. Otherwise it is
classified as Partial, an Intentional Rule, or a Hard Limit.
## Architectural Boundaries
- Do not copy substantial ZendVM executor logic into PHPX.
- Do not add a public PHPX API for one compiler edge case.
- Do not expose raw `zval *`, HashTable slots, or other Zend storage details to
generated project code.
- A new PHPX API must describe a general operation, fit the existing naming and
ownership model, and remain useful outside one PHPT reproducer.
- Emit a native fast path only when the compiler can prove it is safe.
- Prefer a clear TypePHP-specific rule or diagnostic over a large dynamic
compatibility layer.
- A statically known invalid operation should fail during compilation. A
runtime-only invalid operation may use a stable PHPX error; its exact Zend
error level, wording and timing are not part of the compatibility promise.
## Review Decision
Before accepting a compatibility change, answer these questions:
1. Does the issue crash, corrupt memory/data, generate invalid C++, bypass a
type rule, or break a common construct?
2. Can the compiler prove the required dispatch or evaluation order?
3. Can the fix use existing compiler and PHPX abstractions?
4. If a new API is proposed, is it independently useful and correctly placed?
5. Will the implementation remain valid across supported PHP versions without
tracking private ZendVM code?
If the first answer is no and the remaining answers expose disproportionate
complexity, document the boundary instead of implementing it.
## Dimension-Assignment Example
For `$container[$key] ??= $value`, the important behavior is:
- a real array writes its bucket;
- an `ArrayAccess` object uses `offsetExists()`, `offsetGet()` and
`offsetSet()` in the correct branch;
- ordinary receiver, key and RHS expressions are not evaluated more than
required;
- assigning to the temporary returned by `offsetGet()` is never treated as an
object-dimension write.
These are common correctness requirements. By contrast, exact Zend behavior
when callbacks rebind the container or key between phases, deprecated
false-to-array conversion, every string-offset result detail, and exact warning
ordering are edge compatibility. They must not cause PHPX to duplicate the
ZendVM dimension executor.
TypePHP intentionally treats a null array key as append. This established
language difference must be preserved unless a separate design decision changes
it.
## Documentation and Tests
- Every intentional or partial incompatibility must be recorded in
`INCOMPATIBLE_PHP_FEATURES.md` and classified in
`PHP_INCOMPATIBILITY_CLASSIFICATION.md` when appropriate.
- Regression tests should protect the supported boundary, not require behavior
that the project deliberately does not promise.
- Do not make exact diagnostic text part of a test unless the diagnostic is a
stable TypePHP contract.
- A test-only gap is normally completed after a sound implementation; it is not
a reason to accept an unsound architecture.

@ -135,6 +135,13 @@ incompatible with or more restrictive than standard PHP.
## Expressions and control flow
- Dynamic dimension writes use PHPX's array/object/string abstractions. Exact
ZendVM behavior is not promised when a key expression, `ArrayAccess` callback,
or right-hand side rebinds the container or key between the read and write
phases. Unsupported scalar containers raise a stable PHPX error instead of
reproducing every Zend conversion, deprecation, and diagnostic detail.
- TypePHP intentionally treats a null array key as an append operation rather
than converting it to an empty-string key.
- A `match` arm condition may not itself be a `match` expression.
- The value target in a by-reference `foreach` may only be a variable.
- `foreach` list destructuring does not support binding elements by reference.

@ -11,7 +11,7 @@ The goal is to distinguish:
- Partial support where the current behavior is known to differ from PHP.
The main compatibility checklist remains
[INCOMPATIBLE_PHP_FEATURES.md](en/INCOMPATIBLE_PHP_FEATURES.md). This document
[INCOMPATIBLE_PHP_FEATURES.md](INCOMPATIBLE_PHP_FEATURES.md). This document
explains how those items should be interpreted.
## Categories
@ -111,6 +111,7 @@ These items should be documented with the exact boundary.
| Dynamic properties and dynamic property chains | Partial | Dynamic property reads and writes use the runtime property API; native property optimization is not guaranteed. |
| Native typed properties | Partial / Intentional Rule | Fast native paths may not preserve every PHP dynamic state transition. Unknown or incompatible values can fall back to `setProperty()`. |
| Reflection metadata | Partial | Runtime declarations preserve constructor-promotion and asymmetric-visibility flags; other AOT-specific metadata may still be incomplete. |
| Dynamic dimension assignment | Partial / Intentional Rule | Ordinary array and `ArrayAccess` paths must remain correct, but callback-driven container/key rebinding, deprecated scalar conversions, exact string-offset results, and diagnostic ordering are not promised to mirror ZendVM. A null array key is intentionally treated as append. |
## Self-hosting Compatibility Notes

@ -6,6 +6,7 @@ This directory contains compiler implementation, compatibility, build-mode, and
- [AOT and PHP Incompatible Features Checklist](INCOMPATIBLE_PHP_FEATURES.md): a concise list of current limitations.
- [Incompatibility Classification](PHP_INCOMPATIBILITY_CLASSIFICATION.md): distinguishes Hard Limit, Intentional Rule, Pending, and Partial.
- [Compatibility Engineering Policy](COMPATIBILITY_POLICY.md): prioritization, PHPX abstraction boundaries, and review rules for PHP compatibility work.
- [Compiler CLI](COMPILER_CLI.md): current CLI arguments and project configuration.
- [Compilation Modes](COMPILATION_MODES.md): binary, extension, library modes.
- [Quick Start](QUICKSTART.md): the minimal compile flow.

@ -0,0 +1,68 @@
# TypePHP 兼容性工程准则
TypePHP 的目标是保证常规应用代码正确、类型安全、稳定且高效,而不是复刻
ZendVM 每一个可观察的边缘行为。当 PHP 的精确兼容性与 PHPX 封装性、长期
可维护性或静态编译模型冲突时,应优先保护架构,并明确记录行为差异。
## 优先级
| 优先级 | 必须处理的范围 | 示例 |
|---|---|---|
| P0 | 崩溃、UAF、内存破坏、生命周期错误、生成非法 C++、静默破坏数据 | Cache 域混淆、对象生命周期错误、特定后端崩溃 |
| P1 | 常用语法产生明显错误结果、类型检查被绕过、普通副作用表达式被重复求值 | `ArrayAccess` 赋值错误写入 `offsetGet()` 临时值;receiver 被执行两次 |
| P2 | 依赖动态引用、回调、警告或废弃转换的低频组合 | 操作期间由回调把 array 改成 object;警告产生顺序 |
| 非目标 | 只为低频兼容细节而镜像 ZendVM 内部实现 | 向 PHPX 复制大量 `zend_execute.c``zend_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 契约,否则测试不应锁死完整报错文本。
- 仅缺少测试通常可以在可靠实现合入后补齐,但不能为了满足测试接受错误的架构。

@ -61,6 +61,11 @@
## 表达式与控制流
- 动态维度写入使用 PHPX 的 array/object/string 抽象。当 key 表达式、
`ArrayAccess` 回调或右值在读写阶段之间重新绑定 container/key 时,不承诺
复刻 ZendVM 的全部行为。不支持的标量 container 会抛出稳定、统一的 PHPX
错误,而不是复刻 Zend 的全部转换、废弃警告和诊断细节。
- TypePHP 明确将 null 数组 key 视为追加操作,而不是转换为空字符串 key。
- `match` 的 arm condition 不能是 `match` 表达式。
- `foreach` by reference 的 value 只能是变量。
- `foreach` list destructuring 不支持按引用绑定元素。

@ -6,6 +6,7 @@
- [AOT 与 PHP 不兼容特性清单](INCOMPATIBLE_PHP_FEATURES.md):当前限制的简明清单。
- [不兼容性分类](PHP_INCOMPATIBILITY_CLASSIFICATION.md):区分 Hard Limit、Intentional Rule、Pending 和 Partial。
- [兼容性工程准则](COMPATIBILITY_POLICY.md):PHP 兼容性工作的优先级、PHPX 抽象边界与 Code Review 规则。
- [编译器命令行](COMPILER_CLI.md):当前 CLI 参数和项目配置。
- [编译模式](COMPILATION_MODES.md):binary、extension、library 模式。
- [快速入门](QUICKSTART.md):最小编译流程。

Loading…
Cancel
Save