我一直在玩AUTOLOAD
来在Perl中创建我的访问者,我遇到了这种混乱(我已经搜索过google和perldoc)。
我有这段代码:
package Class;
sub new {
..code for constructor here.
}
sub AUTOLOAD {
my $name= shift;
print $name;
}
但是,当我执行以下操作时:my $a=Class->new;
自动加载子例程仍然执行,并打印Class=HASH(some weird number)
;
我认为AUTOLOAD仅在存在未定义的方法或子例程时运行?
我也这样做了:
my $class = our $AUTOLOAD;
print $class #prints ::DESTROY
当我假设没有未定义的函数传递时DESTROY
是$ AUTOLOAD的值时,我是对的吗?
答案 0 :(得分:7)
使用Autoload本质上很困难。如果你想要一个为你提供访问器的实体对象系统,那么请使用Moose,Mouse,Moo ,或者只是遍历你的字段并自己安装访问者:
BEGIN {
my @fields = qw/foo bar baz/;
for my $field (@fields) {
no strict 'refs';
# install a closure in the package stash.
*{ __PACKAGE__ . "::" . $field } = sub {
my $self = shift;
$self->{$field} = shift if @_;
return $self->{$field};
};
}
}
如果一个可以AUTOLOAD
遇到未定义方法的类,则使用缺失子的参数调用AUTOLOAD
子。请求子的完全限定名称在$AUTOLOAD
包变量中传递。
典型的Autoload sub看起来像:
use Carp;
my %fields_allowed = map {$_ => 1} qw/foo bar baz/;
sub AUTOLOAD {
my $field = our $AUTOLOAD;
$field =~ s/.*:://; # strip the package name
$fields_allowed{$field}
or croak qq(Can't locate object method $field via package "@{[__PACKAGE__]}");
my $self = shift;
$self->{$field} = shift if @_;
return $self->{$field};
}
还有两个问题:
DESTROY
方法,则会调用该方法。我们可以通过提供空实施来阻止DESTROY
的自动加载:sub DESTROY {}
。say "Good dog" if $dog->can("roll")
。因此,我们必须覆盖can
以支持我们的自动加载。 can
方法对于安全的鸭子打字非常有用。每个对象都继承自UNIVERSAL
,它为can
和isa
提供默认实现。 can
的合同是它采用方法的名称。当对象无法执行该方法时,它将返回undef
,如果可以,则返回该方法的代码引用。合适的实施方式是
sub can {
my ($self, $name) = @_;
# check if it's a field of ours
if ($fields_allowed{$name}) {
return sub {
my $self = shift;
$self->{$name} = shift if @_;
return $self->{$name};
};
}
# Ask SUPER implementation of can if we can do $name
if (my $meth = $self->SUPER::can($name)) {
return $meth;
}
return; # no method found
}
我们现在可以将AUTOLOAD
简化为
sub AUTOLOAD {
my $field = our $AUTOLOAD;
$field =~ s/.*:://; # strip the package name
my $code = $self->can($field)
or croak qq(Can't locate object method $field via package "@{[__PACKAGE__]}");
goto &$code; # tail call; invisible via `caller()`.
}
要想做到这一点,这很复杂。结论:不要使用Autoload,因为您认为它可能不那么重要。它永远不会。它对于实现代理模式非常有用,但这有点高级。
在深入了解Perl独特而奇特的功能之前,我恳请您使用OO基础知识和Moose对象系统。