2010-03-17 48 views
9

Trong "Perl Best Practices" dòng đầu tiên trong phần trên Autoload là:Khi nào tôi nên sử dụng AUTOLOAD của Perl?

Không sử dụng Autoload

Tuy nhiên tất cả các trường hợp ông mô tả đang đối phó với OO hoặc Modules.

Tôi có một tập lệnh độc lập trong đó một số công tắc dòng lệnh kiểm soát phiên bản của các chức năng cụ thể được xác định. Bây giờ tôi biết tôi chỉ có thể lấy các điều kiện và evals và dính chúng trần truồng ở trên cùng của tập tin của tôi trước khi mọi thứ khác, nhưng tôi thấy nó thuận tiện và sạch hơn để đặt chúng trong AUTOLOAD ở phần cuối của tập tin.

Thực tiễn/phong cách này có tệ không? Nếu bạn nghĩ vậy tại sao, và có cách nào khác để làm điều đó không?

Theo yêu cầu của brian của

Tôi đang sử dụng về cơ bản này để làm biên soạn có điều kiện dựa trên công tắc dòng lệnh.

Tôi không quan tâm đến một số lời chỉ trích mang tính xây dựng.

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 ([email protected]) { 
      eval q(sub grow {}); 
     } 
     goto &$method; 
    } else { 
     eval "sub $method {}"; 
     return; 
    } 
    die [email protected] if [email protected]; 
    goto &$method; 
} 
+1

Ví dụ về những gì bạn đang làm sẽ cải thiện cuộc thảo luận. :) –

Trả lời

1

Nếu lý do duy nhất của bạn để sử dụng AUTOLOAD là di chuyển khối đến cuối, tại sao không đặt nó ở cuối chương trình con, và sau đó gọi nó ngay sau khi biến phụ thuộc của nó được xác định?

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 

Vẫn còn tốt hơn, nếu các hình cầu không cần thiết ở nơi khác, chỉ cần chuyển giá trị cho compile làm đối số.

+0

@Eric Strom: Vì vậy, bạn cảm thấy đây là phong cách tốt hơn và sạch hơn so với 'AUTOLOAD'? Nó dường như giống hệt với những gì tôi đang làm với 'AUTOLOAD', ngoại trừ việc tôi phải gọi' biên dịch' một cách rõ ràng ở đầu chương trình. Tại sao điều này tốt hơn là ngầm gọi 'AUTOLOAD' lần đầu tiên một hàm được gọi? Giải pháp rất thú vị vì tôi đã không thấy cú pháp '* name = sub {...}' trước đây. –

+1

@Robert S.Barnes => 'AUTOLOAD' mang theo nó một chút hành lý: các biến chứng với thừa kế, tốc độ, yêu cầu các subs được gọi là phương thức. Đó là tất cả những tệ nạn cần thiết nếu bạn đang làm một cái gì đó thực sự cần 'AUTOLOAD', nhưng nếu không, nó có thể chỉ là một nguồn gốc của lỗi. Tốt nhất để làm giải pháp đơn giản nhất hoạt động. Riêng biệt, bằng cách sử dụng cú pháp phụ anon chứ không phải là chuỗi eval cho phép perl để bắt lỗi tại thời gian biên dịch chứ không phải là thời gian chạy. –

6

Tôi nghĩ một kịch bản độc lập cách tiếp cận này là OK. Bạn có thể tạo các chương trình con đang chạy để tăng tốc các cuộc gọi tiếp theo, ví dụ:

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 
} 

Tự động nạp là khó khăn khi sản xuất cây thừa kế.

7

Một chiến lược thay thế sẽ là viết tập lệnh dưới dạng mô-đun App :: * và có tùy chọn dòng lệnh chọn lớp cần tải để cung cấp bất kỳ chức năng nào mà plugin có thể cắm tùy thuộc vào tùy chọn. Bạn sẽ require rằng lớp học chỉ trong thời gian khi bạn biết nó là gì. Đó là một công việc phía trước nhiều hơn một chút, nhưng nếu bạn có ý định duy trì kịch bản trong một thời gian dài, tôi đặt cược nó sẽ trả hết. Vài năm qua đã thấy việc tạo ra một số công cụ cực kỳ hay để tạo các tập lệnh có chức năng thực sự tồn tại trong các mô-đun, bao gồm App::Cmd, MooseX::Getoptthe bastard offspring of both.

+0

Nghe có vẻ thú vị và đáng để kiểm tra, mặc dù tôi nghĩ rằng nó có thể là quá mức cần thiết cho những gì tôi đang làm. Nó chỉ là một kịch bản dòng 500. –

+0

500 được cho là khoảng 450 quá nhiều. :) – hobbs

Các vấn đề liên quan