5

メンテナンスを実行するために使用される Perl スクリプトを使用しています。より多くのタスクを処理できるように変更する必要がありました。問題は、スクリプトがコンパイルされ、ソースがずっと前に失われたことです。

ファイルを再作成するために B::Deparse を使用しようとしましたが、Deparse は完全ではなく、出力が壊れています (非常に大きな ~5000 行の逆解析コード)。

デパースさ​​れたコードを読んだ後、1​​ つの関数を変更する必要があることがわかりました。コンパイルされたスクリプトはプレーンテキストのスクリプト モジュールをロードするので、モジュールを変更して関数をオーバーライドし、必要なタスクを実行します。問題は、メイン スクリプトの "my" 変数にアクセスできないことです。

次に例を示します。

# 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";
}

結果は次のとおりです: " $main::a =" 実際の値を取得する代わりに。

前もって感謝します。

4

2 に答える 2

8

簡単に言えば、 で宣言された変数はmy、レキシカル スコープの外ではアクセスできないということです。宣言を "our" に変更できない場合 (元のスクリプトのクレイジーな "コンパイル済み" の性質のため)、まだ運が悪いわけではありません。Perl はほとんどの場合、これらの種類のものを回避する方法を提供します。

この場合、PadWalkerモジュールをインストールして、次のようなことを行うことができます (最初に投稿したコードを微調整したバージョンを次に示します)。

main.plスクリプト:

my $a = 1;

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

use MOD;

call_me;

そして、あなたのモジュール:

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";
    }
}
于 2012-07-13T20:51:17.753 に答える