我一直在玩AUTOLOAD
Perl创建我的访问器,我遇到了这种困惑(我已经搜索过google和perldoc).
我有这个代码:
package Class;
sub new {
..code for constructor here.
}
sub AUTOLOAD {
my $name= shift;
print $name;
}
Run Code Online (Sandbox Code Playgroud)
但是,当我做类似的事情时:my $a=Class->new;
自动加载子程序仍然执行,并打印Class=HASH(some weird number)
;
我以为AUTOLOAD只在有未定义的方法或子程序时运行?
我也是这样做的:
my $class = our $AUTOLOAD;
print $class #prints ::DESTROY
Run Code Online (Sandbox Code Playgroud)
当我DESTROY
没有传递未定义的函数时,我认为这是$ AUTOLOAD的值,我是对的吗?
使用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};
};
}
}
Run Code Online (Sandbox Code Playgroud)
如果一个类可以AUTOLOAD
遇到未定义的方法,AUTOLOAD
则使用缺少的sub的参数调用sub.请求的子的完全限定名称在$AUTOLOAD
包变量中传递.
一个典型的Autoload子看起来像:
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};
}
Run Code Online (Sandbox Code Playgroud)
还有两个问题:
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
}
Run Code Online (Sandbox Code Playgroud)
我们现在可以简化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()`.
}
Run Code Online (Sandbox Code Playgroud)
要做到这一点很复杂.结论:不要使用Autoload,因为您认为它可能不那么重要.它永远不会.它对于实现代理模式非常有用,但这有点高级.
在深入了解Perl独特而奇特的功能之前,我强烈建议您使用OO基础知识和Moose对象系统.