2012-07-13 22 views
5

Chúng tôi có một tập lệnh Perl được sử dụng để thực hiện bảo trì. Tôi cần phải sửa đổi nó để xử lý nhiều công việc hơn. Vấn đề là kịch bản được biên dịch và nguồn đã bị mất từ ​​lâu.Perl: Truy cập các biến 'của tôi' từ một tệp khác

Tôi đã cố gắng sử dụng B :: Deparse để tạo lại tệp nhưng Deparse không hoàn hảo và đầu ra bị hỏng (và rất lớn ~ 5000 dòng mã được deparsed).

Sau khi đọc mã bị bỏ qua, tôi thấy rằng tôi cần phải sửa đổi một chức năng. Kịch bản đã biên dịch tải một mô-đun tập lệnh văn bản thuần tuý, vì vậy tôi đã thay đổi mô đun để ghi đè hàm và thực hiện tác vụ tôi cần để thực hiện. Vấn đề bây giờ là tôi không thể truy cập vào các biến "my".

Dưới đây là một ví dụ:

# main.pl 

my $a = 1; 

sub call_me { 
    print "unmodified"; 
} 

use MOD; 

call_me; 


MOD.pm 
package MOD; 

main::{'call_me'} = sub { 
    print "\$main::a = $main::a\n"; 
} 

Kết quả là: "$main::a =" thay vì nhận được giá trị thực.

Xin cảm ơn trước.

+0

Biến số ('my') không bật lên trong bảng biểu tượng của gói trái ngược với hình cầu gói. Vì vậy, đây là một khó khăn, nhưng một trong những thú vị ... # Sidenote: bạn chỉ có thể viết phụ chính :: call_me {...} nếu tôi nhớ chính xác. – amon

+0

Ý bạn là gì bởi "tập lệnh được biên dịch". Bạn có nghĩa là đóng gói? – ikegami

+0

Tôi đồng ý với ikegami, có thể có một số cách để khôi phục tập lệnh đó, nhưng để biết, chúng tôi cần biết ý của bạn là "biên soạn". –

Trả lời

8

Câu trả lời ngắn gọn là các biến được khai báo với my không thể truy cập được bên ngoài phạm vi từ vựng của chúng. Nếu bạn không thể thay đổi tuyên bố thành "của chúng tôi" (vì bản chất "biên soạn" điên rồ của tập lệnh gốc), bạn chưa hết may mắn. Perl hầu như luôn luôn cung cấp một cách xung quanh những thứ này.

Trong trường hợp này, bạn có thể cài đặt các module PadWalker và làm điều gì đó như thế này (đây là một phiên bản tinh chỉnh mã gửi ban đầu của bạn):

Các main.pl kịch bản:

my $a = 1; 

sub call_me { 
    print "unmodified: $a"; 
} 

use MOD; 

call_me; 

Và sau đó mô-đun của bạn :

package MOD; 

# closed_over($code_ref) returns a hash ref keyed on variable 
# name(including sigil) with values as references to the value 
# of those variables 
use PadWalker qw(closed_over); 

{ 
    # grab a reference to the original sub 
    my $orig = \&main::call_me; 

    # no need to use the symbol table, a glob reference is fine 
    # but you can't use sub main::call_me { ... } either 
    *main::call_me = sub { 
     my $a = closed_over($orig)->{'$a'}; 
     print "\$main::a = $$a\n"; 
    } 
} 
+0

hoạt động như một sự quyến rũ! cảm ơn rất nhiều – user1247066

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