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.1 KiB

Std 容器参数类型注解

StdArray、StdVector、StdMap、StdOrderedMap 是 TypePHP 内置的 Box 容器类型注解。 它们描述容器种类和元素类型,并自动完成以前需要手写的 toStd*() 类型恢复。

本文记录现有 Box 容器参数实现。包含 StdList / StdDict 的统一规则见 类型注解统一设计;拟议函数签名见 StdFunc / StdArgInfo。

function append(#[StdVector(Type::Int)] $vec): void
{
    $vec[] = 42;
}

function update_matrix(#[StdArray(Type::Int, [2, 3])] box $matrix): void
{
    $matrix[1][2] = 42;
}

function update(#[StdMap(Type::String, User::class)] $users): void
{
    $users['alice'] = new User();
}

function visit(#[StdOrderedMap(Type::Int, Type::String)] $names): void
{
    foreach ($names as $key => $value) {
        echo $key, ':', $value, "\n";
    }
}

声明规则

  • 一个参数只能有一个容器类型注解,不能重复或混用。
  • 类型注解提供完整契约,PHP 参数类型可以省略或声明为兼容的 box;不能声明 mixed、any、array、Nullable、联合类型或其他不兼容类型。
  • StdArray 接受叶子类型及单长度或外到内维度数组;StdVector 接受一个类型实参;StdMap、StdOrderedMap 接受 key/value 两个类型实参。
  • 类型实参使用现有 std 工厂支持的 Type::* 或 ClassName::class;map 的 key 只支持 Type::Int、Type::String。
  • 使用位置为具名函数和方法参数,包括接口、抽象方法和 trait 方法;支持 Attribute 别名导入。
  • 首版不支持引用、可变、带默认值、构造器属性提升参数,以及 Closure、箭头函数和 Generator 参数。
  • 容器内不能保存 Native 对象并通过 Box 参数边界传递;原有 Native 容器逃逸限制不变。
  • 参数绑定不能换成其他 Box/值、unset() 或被 Closure 按引用捕获;同类型 std 容器赋值仍按现有规则复制内容。元素的读取、更新、追加和遍历继续遵循现有 std 容器规则。

以下声明会产生编译错误:

function invalid(#[StdVector(Type::Int)] mixed $vec): void {}

调用和生命周期

函数的底层调用 ABI 仍为 php::Var,容器仍由 Box 管理生命周期。编译器在入口 检查 Box、容器种类及元素类型,取得具体 C++ 容器引用;不复制容器,也不逐个转换元素。 错误的容器类型、PHP 数组及其他非 Box 实参会产生 TypeError。

函数中修改容器内容时,调用者可观察到相同修改:

$vec = std::vector(Type::Int);
append($vec);
var_dump($vec[0]); // int(42)

现有动态调用把已知 std 容器转换为 PHP 数组的规则不变。如果通过动态 callable 调用这类函数,需传入实际的 Box 值,而不是已经转换成 PHP 数组的值。 注解不会让普通 Zend PHP 获得 C++ 泛型容器支持,也不会把 C++ 模板类型变成 PHP 的原生参数类型。

容器契约保存在声明缓存和导出的 library stub 中。修改参数注解会使源文件及依赖它的 调用方重新转换;仅复用缓存时,入口类型恢复仍然保留。