Perlでレキシカル変数を外部からいじる方法

読了まで:約1分


概要: Perl でレキシカル変数を外部のスコープから変更する Tips


外部スコープからレキシカル変数の値を変更する、 という普通んなことしねーよな変態なことをやりたかったので、 やる方法をだいぶ前に調べたことをまとめてみる。

結論から言えば PadWalker を使えばできる。

使い方はまあこんな感じ。細かいことは POD 見れば分かるので説明は省略。

use strict;
use warnings;
use PadWalker qw( peek_my );
use Perl6::Say;
{
my $x = 'foo';
say $x; # 'foo'
&magic();
say $x; # 'bar'
}
sub magic {
my $vars = peek_my(1);
${ $vars->{'$x'} } = 'bar';
}

で、まあ何でレキシカル変数を外部から書き換えるとか変態的なことがしたかったかというと、 blosxom のプラグインの設定を プラグインファイル自体を書き換えずに 変更したかったから。 要するにプラグインの設定を外部ファイルに一まとめにしたかったって言う。

blosxom のプラグインは設定がpackageの直下myで定義されてるので普通は外から変更できない。 で、最初peek_myでできるかと思ってたんだけど、色々やってみても結局できなかった。

んで、どうしたもんかとやっていたうちに、 peek_sub使えばできるんじゃね? というのを思いついて、 実際に試してみたらできちゃったという。大体こういう感じでできた。

package foo;
my $confA = 'AAA';
my $confB = 'BBB';
sub start {
return 1;
}
package bar;
use PadWalker qw( peek_sub );
my $start_sub   = foo->can('start');
my $vars        = peek_sub( $start_sub );
${ $vars->{'$confA'} } = 'BBB';
${ $vars->{'$confB'} } = 'BBB';

どういうことかと言うと、$confA,$confBpackage直下で定義されてるので、 関数start内のスコープからでも参照できる 。 んで、peek_sub関数のスコープ内のレキシカル変数を取得する ことができるので、

レキシカル変数を参照できるスコープを持つ CODE reference を取得し、その CODE reference からpeek_subを使ってレキシカル変数を取得できる というわけ。

言葉にするとややこしい気がしないでもないけど、コード見れば大体分かると思う。

まあそういうことが分かったのでまあプラグインの設定を外部ファイルに切り出すプラグインはできたものの blosxom いじりが途中で止まってるので 公開してなかったりする。もうちょっといじって CodeRepos に上げる予定はしてるけど。

なんか久しぶりに空繰再繰更新した。もうちょっと更新頻度上げたい。

追記

どうも嘘書いてたっぽい 。

今日気付いたんだけど、上記の方法では サブルーチンで参照していない変数 は参照できないもよう。

どうしたもんかな、これ。

#FIXME

にゃるら(カラクリスタ)

『輝かしい青春』なんて失かった人。
次に備えて待機中。

今は趣味でプログラミングをして
生活しています。