以下是Perl 5.12上的调试会话。这有意义吗? 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
吗?
答案 0 :(得分:14)
Class::ISA::self_and_super_path
的替换为mro::get_linear_isa
。这可以从mro
本身获得,或者,如果您想通过MRO::Compat
支持旧的perls,则可以使用。
此外,@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
,这将使方法解析缓存无效,这些缓存绑定到各种@ISA
秒。
如果你可以将这个bug减少到一个最小的测试用例,这对于修复这个bug非常有帮助。
<强>更新强>
最小的测试用例变得简单:
$ 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
和常规作业都能正确完成,因此使用其中一项可以解决您的问题。
另一个更新:
This change,我刚刚致力于perl,修复了这个问题。然而,由于splice
没有调用魔法的奇怪行为已经出现在5.8和5.10中,它不是回归,因此在几个月内不会成为5.12.3的一部分。将于下周发布的5.13.6和下一个北方春季的5.14.0可能会有它。
答案 1 :(得分:4)
是的,有一个缓存。但是,如果您可以修改@ISA
而不使该缓存失效,我会认为这是perl中的错误。
如果在@ISA = @ISA;
行之后添加行splice
,问题是否会消失?