我无法弄清楚多态如何在Perl中工作的解释.我理解多态性意味着什么,但我想弄清楚它在perl中的内部工作原理.有人能指出一些解释它的文档.我所做的所有谷歌搜索都给出了perl中多态性的例子,但不是perl如何使其工作.
Bor*_*din 15
当在对象或类上调用方法时,Perl会查看该方法是否由类本身直接提供.
因为类只是Perl包,所以只需要查找子例程的存在&Class::method
.
如果没有找到这样的子例程,Perl会检查@ISA
同一个包(即@Class::ISA
)中包含该类的基类列表的数组,并对其中出现的每个包/类进行相同的检查.
这些类中的每一个依次也可以有一个@ISA
数组,因此搜索是递归的.
最后,如果通过此方法找不到该方法,Perl会在特殊包中UNIVERSAL
查找子例程&UNIVERSAL::method
.
此时失败继续调用AUTOLOAD
系统,但这实际上超出了多态性的原则.
无法在任何地方找到合适的匹配方法会引发异常.
面向对象Perl的第7章,Damian Conway,Manning(2000)被称为多态.十页.
但是,请注意,如果您来自C++或Java或C#或类似的,那么Perl中的"多态性"并不是很多.我甚至会说多态性的概念比Perl中的事情更复杂.
我认为Perl程序员应该努力理解的机制是方法查找的工作原理.答案是:深度优先递归扫描@ISA
包的数组.
举个例子,我们来做$o->bla
.我们$o
有幸得到了A
包,没有实现bla
.但它继承自first B
和then C
(@ISA = ('B', 'C')
).所以我们先做一下查找B
.它也没有定义方法.如果它有父类,我们将继续在那里查找.但事实并非如此.所以我们现在调查一下C
,幸运的是它确实有方法,否则这将是一个运行时错误,因为最后的包UNIVERSAL
,也没有定义bla
.
对象方法调用基本上是以下内容的优化*版本:
my $class = ref($_[0]);
my @isa = mro::get_linear_isa($class);
for my $pkg (@isa) {
if (exists(&{$pkg.'::'.$method_name})) {
return &{$pkg.'::'.$method_name};
}
}
Run Code Online (Sandbox Code Playgroud)
ref
获取与对象关联的类的名称。该类存储在对象的变量中。
$ perl -MDevel::Peek -e'my $o = {}; Dump($o); bless($o, "SomeClass"); Dump($o);'
SV = IV(0x9e4ae0c) at 0x9e4ae10
REFCNT = 1
FLAGS = (PADMY,ROK)
RV = 0x9e317d0
SV = PVHV(0x9e36808) at 0x9e317d0
REFCNT = 1
FLAGS = (SHAREKEYS)
ARRAY = 0x0
KEYS = 0
FILL = 0
MAX = 7
RITER = -1
EITER = 0x0
SV = IV(0x9e4ae0c) at 0x9e4ae10
REFCNT = 1
FLAGS = (PADMY,ROK)
RV = 0x9e317d0
SV = PVHV(0x9e36808) at 0x9e317d0
REFCNT = 1
FLAGS = (OBJECT,SHAREKEYS) <----
STASH = 0x9e323d0 "SomeClass" <----
ARRAY = 0x0
KEYS = 0
FILL = 0
MAX = 7
RITER = -1
EITER = 0x0
Run Code Online (Sandbox Code Playgroud)
get_linear_isa
基于@ISA
in package $class
和@ISA
其中命名的包。
由于类名称位于对象中,并且Perl可以在运行时检查其符号表,因此不需要虚拟方法表来提供多态性。
* —缓存哪个包为类$ class提供了方法$ method_name。此外,它当然不会预先计算整个线性ISA,而是根据需要计算。