Когда я должен использовать Perl AUTOLOAD? - PullRequest
9 голосов
/ 17 марта 2010

В " Perl Best Practices " самая первая строка в разделе об автозагрузке:

Не использовать AUTOLOAD

Однако все описанные им случаи имеют дело с ОО или Модулями.

У меня есть автономный скрипт, в котором некоторые ключи командной строки управляют определением версий определенных функций. Теперь я знаю, что могу просто взять условные выражения и уловки и прикрепить их голыми в верхней части моего файла, прежде чем что-либо еще, но я считаю, что удобнее и чище помещать их в 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;
}

Ответы [ 3 ]

7 голосов
/ 17 марта 2010

Альтернативная стратегия заключается в написании сценария в виде модуля App :: *, и параметр командной строки выбирает, какой класс загружать, чтобы обеспечить любую функциональность, которая является подключаемой, в зависимости от параметра. Вы бы require этот класс как раз вовремя, как только вы знаете, что это такое. Это немного более предварительная работа, но если вы собираетесь поддерживать сценарий в течение длительного времени, я уверен, что он окупится. За последние пару лет было создано несколько очень хороших инструментов для создания сценариев, функциональность которых действительно присутствует в модулях, включая App :: Cmd , MooseX :: Getopt и * 1006. * ублюдок потомства обоих .

6 голосов
/ 17 марта 2010

Я думаю, что для автономного сценария этот подход в порядке. Вы можете создавать подпрограммы на лету, чтобы ускорить последующие вызовы, например:

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
}

Автозагрузка сложна при создании деревьев наследования.

1 голос
/ 18 марта 2010

Если ваша единственная причина использования 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 в качестве аргументов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...