我什么时候应该使用Perl的AUTOLOAD?

时间:2010-03-17 08:43:25

标签: perl coding-style

在“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;
}

3 个答案:

答案 0 :(得分:7)

另一种策略是将脚本编写为App :: *模块,并使用命令行选项选择要加载的类,以提供可插拔的功能,具体取决于选项。一旦你知道它是什么,你就会及时require那个班级。这是一个前期工作,但如果你打算长时间维护脚本,我敢打赌它会得到回报。在过去几年中,创建了一些非常好的工具,用于创建功能真正存在于模块中的脚本,包括App::CmdMooseX::Getoptthe 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