perlmroapi - Perl 方法解析插件接口
从 Perl 5.10.1 开始,有一个新接口用于插入和使用除默认值(线性深度优先搜索)之外的方法解析顺序。5.10.0 中添加的 C3 方法解析顺序已重新实现为一个插件,而无需更改其 Perl 空间接口。
每个插件都应通过提供以下结构注册自身
struct mro_alg {
AV *(*resolve)(pTHX_ HV *stash, U32 level);
const char *name;
U16 length;
U16 kflags;
U32 hash;
};
并调用 Perl_mro_register
Perl_mro_register(aTHX_ &my_mro_alg);
指向线性化函数的指针,如下所述。
MRO 的名称,以 ISO-8859-1 或 UTF-8 编码。
名称的长度。
如果名称以 UTF-8 编码,则将其设置为 HVhek_UTF8
。该值作为参数 kflags 直接传递给 hv_common()
。
MRO 名称的预计算哈希值,或 0。
resolve
函数被调用来使用此 MRO 为给定的 stash 生成线性 ISA。它使用指向 stash 的指针和 0 的级别进行调用。当核心调用你的函数时,它总是将级别设置为 0 - 提供该参数是为了允许你的实现跟踪深度,如果它需要递归的话。
该函数应返回对包含字符串 SV 的数组的引用,该数组按顺序提供父类的名称。类的名称应为在 stash 上调用 HvENAME()
的结果。在 HvENAME()
返回 null 的情况下,应使用 HvNAME()
代替。
调用方负责增加返回的数组的引用计数(如果它想保留该结构)。因此,如果你创建了一个不保留指向它的指针的临时值,则 sv_2mortal()
可确保正确处理它。如果你已缓存你的返回值,则返回指向它的指针,而不更改引用计数。
计算 MRO 可能很昂贵。该实现提供了一个缓存,你可以在其中存储一个 SV *
,或任何可以强制转换为 SV *
的内容,例如 AV *
。要读取你的私有值,请使用宏 MRO_GET_PRIVATE_DATA()
,将 stash 中的 mro_meta
结构和指向你的 mro_alg
结构的指针传递给它
meta = HvMROMETA(stash);
private_sv = MRO_GET_PRIVATE_DATA(meta, &my_mro_alg);
要设置你的私有值,请调用 Perl_mro_set_private_data()
Perl_mro_set_private_data(aTHX_ meta, &c3_alg, private_sv);
私有数据缓存将获取对 private_sv 的引用的所有权,这与 hv_store()
获取你传递给它的值的引用的所有权的方式非常相似。
有关 MRO 实现的示例,请参阅 ext/mro/mro.xs 中的 S_mro_get_linear_isa_c3()
和 BOOT:
部分,以及 mro_core.c 中的 S_mro_get_linear_isa_dfs()
perl 核心中的 C3 MRO 和可切换 MRO 的实现是由 Brandon L Black 编写的。Nicholas Clark 创建了可插拔接口,重构了 Brandon 的实现以使其与之配合使用,并编写了此文档。