以下是Perl 5.12上的调试 session 。这有意义吗? UNIVERSAL
是否缓存@ISA
变量的版本,如果永远使用该变量。早在弃用 Class::ISA
之前,我曾经调用Class::ISA::self_and_super_path
来获取内部结构以重新查看@ISA
数组。由于现在认为它是不必要的,因此您如何让perl审核其内部记录?
DB<34> p $papa
Papushka=HASH(0x16bc0300)
DB<35> p $papa->isa('Nanushka')
DB<36> p $papa->isa('Babushka')
1
DB<37> x @Papushka::ISA
0 'Nanushka'
1 'Babushka'
这是测试代码(很明显)。它获得相同的结果,平稳运行,作为测试运行或在调试中运行。我应该告诉你,在执行
@ISA = qw<Babushka>
之前,我执行了splice( @ISA, 0, 0, 'Nanushka' );
那是问题吗?您应该只将
push
放到@ISA
吗? 最佳答案
Class::ISA::self_and_super_path
的替换为mro::get_linear_isa
。这可以从mro
本身获得,或者,如果您想支持旧的perls,则可以通过MRO::Compat
获得。
另外,@ISA
是一个魔术变量。
$ perl -MDevel::Peek -e'Dump \@ISA'
SV = IV(0x1b92e20) at 0x1b92e28
REFCNT = 1
FLAGS = (TEMP,ROK)
RV = 0x1bbcd58
SV = PVAV(0x1b93cf8) at 0x1bbcd58
REFCNT = 2
FLAGS = (SMG,RMG)
MAGIC = 0x1bc0f68
MG_VIRTUAL = &PL_vtbl_isa
MG_TYPE = PERL_MAGIC_isa(I)
MG_OBJ = 0x1bbcd40
ARRAY = 0x0
FILL = -1
MAX = -1
ARYLEN = 0x0
FLAGS = (REAL)
注意
PERL_MAGIC_isa
。这就是驱动这种特殊机制的原因。每当更改它时,任何依赖于其值的缓存的内容都应被更新。
$ perl -E'say Foo->isa(q[Bar]) || 0; @Foo::ISA = qw(Bar Baz); say Foo->isa(q[Bar]) || 0'
0
1
显然,您发现了一种情况,即不会发生缓存失效。我认为这是一个错误。出于某些原因,
splice
可能没有正确调用isa
魔术。您可以尝试以其他方式修改@ISA
,例如使用unshift
或赋值,或者尝试使用mro::method_changed_in
,这会使绑定(bind)到各种@ISA
的方法解析缓存无效。如果您可以将此错误减少到最小的测试用例,那将对修复此错误非常有帮助。
更新:
最小的测试用例证明很容易:
$ perl -E'say Foo->isa(q[Bar]) || 0; splice @Foo::ISA, 0, 0, q[Bar]; say Foo->isa(q[Bar]) || 0'
0
0
这是由于
pp_splice
没有执行类似mg_set((SV *)ary)
的操作引起的。 push
,unshift
和常规分配可以正确地做到这一点,因此使用其中之一应可解决您的问题。另一个更新:
我刚刚致力于perl的This change修复了该问题。但是,由于5.8和5.10中已经存在
splice
不调用魔术的奇怪行为,因此它不是回归,因此在几个月内不会成为5.12.3的一部分。 5.13.6(将在下周发布)和5.14.0(在下个 Spring )将可能发布。