В "Лучших практиках Perl" самая первая строка в разделе по АВТОЗАГРУЗКЕ:
Не используйте АВТОЗАГРУЗКУ
Однако все случаи, которые он описывает, имеют дело с OO или Модулями.
У меня есть одинокий сценарий, в котором, некоторое управление переключателями командной строки который определяются версии конкретных функций. Теперь я знаю, что мог просто взять условные выражения и evals и засунуть их явный наверху моего файла перед всем остальным, но я нахожу это удобным и более чистым для помещения их в АВТОЗАГРУЗКУ в конце файла.
Эта плохая практика / стиль? Если Вы думаете итак, почему, и там другой способ сделать это?
Согласно запросу brian
Я в основном использую это, чтобы сделать условную компиляцию на основе переключателей командной строки.
Я не возражаю против некоторой конструктивной критики.
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;
}
Если ваша единственная причина для использования 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
в качестве аргументов.
Альтернативной стратегией было бы написать скрипт как модуль App :: * и указать параметр командной строки, какой класс загружать, чтобы обеспечить любую подключаемую функциональность в зависимости от вариант. Вам потребуется
этот класс точно в срок, если вы узнаете, что это такое. Это немного больше предварительной работы, но если вы собираетесь поддерживать сценарий в течение длительного времени, я уверен, что это окупится. За последние пару лет было создано несколько очень хороших инструментов для создания скриптов, функциональность которых действительно заключается в модулях, включая App :: Cmd , MooseX :: Getopt и ] внебрачный отпрыск обоих .
Я думаю, что для автономного скрипта такой подход подходит. Вы можете создавать подпрограммы на лету для ускорения последующих вызовов, например:
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
}
Автозагрузка сложна при создании деревьев наследования.