在“Perl Best Practices”中,AUTOLOAD部分的第一行是:
请勿使用AUTOLOAD
然而,他描述的所有案例都涉及OO或模块。
我有一个独立的脚本,其中一些命令行开关控制定义特定函数的哪个版本。现在我知道我可以采取条件和描述,并在其他所有内容之前将它们裸露在我的文件顶部,但我觉得将它们放在文件末尾的AUTOLOAD中是方便和清晰的。
这是不好的做法/风格吗?如果你这么认为,为什么还有另一种方法呢?
根据布莱恩的要求
我基本上是使用它来根据命令行开关进行条件编译。
我不介意一些建设性的批评。
sub AUTOLOAD {
our $AUTOLOAD;
(my $method = $AUTOLOAD) =~ s/.*:://s; # remove package name
if ($method eq 'tcpdump' && $tcpdump) {
eval q(
sub tcpdump {
my $msg = shift;
warn gf_time()." Thread ".threads->tid().": $msg\n";
}
);
} elsif ($method eq 'loginfo' && $debug) {
eval q(
sub loginfo {
my $msg = shift;
$msg =~ s/$CRLF/\n/g;
print gf_time()." Thread ".threads->tid().": $msg\n";
}
);
} elsif ($method eq 'build_get') {
if ($pipelining) {
eval q(
sub build_get {
my $url = shift;
my $base = shift;
$url = "http://".$url unless $url =~ /^http/;
return "GET $url HTTP/1.1${CRLF}Host: $base$CRLF$CRLF";
}
);
} else {
eval q(
sub build_get {
my $url = shift;
my $base = shift;
$url = "http://".$url unless $url =~ /^http/;
return "GET $url HTTP/1.1${CRLF}Host: $base${CRLF}Connection: close$CRLF$CRLF";
}
);
}
} elsif ($method eq 'grow') {
eval q{ require Convert::Scalar qw(grow); };
if ($@) {
eval q( sub grow {} );
}
goto &$method;
} else {
eval "sub $method {}";
return;
}
die $@ if $@;
goto &$method;
}
答案 0 :(得分:7)
另一种策略是将脚本编写为App :: *模块,并使用命令行选项选择要加载的类,以提供可插拔的功能,具体取决于选项。一旦你知道它是什么,你就会及时require
那个班级。这是一个前期工作,但如果你打算长时间维护脚本,我敢打赌它会得到回报。在过去几年中,创建了一些非常好的工具,用于创建功能真正存在于模块中的脚本,包括App::Cmd,MooseX::Getopt和the bastard offspring of both。
答案 1 :(得分:6)
我认为对于一个独立的脚本,这种方法是可以的。您可以动态创建子程序以加速后续调用,例如:
sub AUTOLOAD {
(my $name = our $AUTOLOAD) =~ s/.*:://;
no strict 'refs'; # allow symbolic references
*$AUTOLOAD = sub { print "$name subroutine called\n" };
goto &$AUTOLOAD; # jump to the new sub
}
生成继承树时自动加载很棘手。
答案 2 :(得分:1)
如果使用AUTOLOAD
的唯一原因是将块重新定位到末尾,为什么不将它放在子例程的末尾,然后在定义其因变量时立即调用它?
sub tcpdump; # declare your subs if you want to call without parens
# define the parameters
compile();
# code that uses new subs
sub compile {
*tcpdump = $tcpdump ? sub {
my $msg = shift;
warn gf_time()." Thread ".threads->tid().": $msg\n";
} : sub {};
# ...
}
# EOF
更好的是,如果其他地方不需要全局变量,只需将值作为参数传递给compile
。