シンボルテーブルとグロブ(2)
おさらい
- シンボルテーブルは普通のPerlハッシュで実装されています。
- Perlのhogeという名前の変数には$hoge, @hoge, %hoge, &hoge, ファイルハンドルのhoge, ディレクトリハンドルのhogeなどがあります。
- これらのhogeは物理的にはバラバラの場所に離れています。
- ただし、それぞれへのリファレンスは同じハッシュ内に含まれています。
- そのハッシュはグロブと呼ばれており、それへのリファレンスはアスタリスクからはじまっています。
- このようにPerlでは変数ルックアップに2つの段階を経て処理しています。
- 最初の段階で、適切なグログをシンボルテーブルから発見します。名前ルックアップ。
- 次の段階ではグロブから求めるべきリファレンスを見つけます。リファレンスルックアップ。
グロブ割り当てによるエイリアス
グロブの仕組みを学ぶと、次のような処理が理解できます。
package Foo; use strict; use warnings; sub test_method { 'hoge' } sub import { no strict 'refs'; *{ caller(). "::test_method"} = *test_method; } 1;
importとcaller
importは何をするのでしょうか?perldocを見てみましょう。例では
%perldoc -f import
Pod::PerldocJpを導入している場合は次のコマンドが便利です。
% perldocjp -Jf import
「"use" 関数はパッケージを使う時に "import" メソッドを呼び出します。」という記述があります。
つまり、use Foo::Bar;と書いたパッケージはimport内の処理を自動的に実行するようにできます。
次にcallerです。同様に調べましょう。
%perldoc -f caller
Pod::PerldocJpを導入している場合は次のコマンドが便利です。
% perldocjp -Jf caller
解説を要約すると、呼び出した名前空間を知ることができる、という事です。
no strict 'refs' に関してはまた次の機会に説明したいと思います。*1興味がある方は perldoc strict;を実行して下さい。
次のコードをご覧ください。このパッケージにはtest_methodというメソッドが生えているという事が分かっている方はもうシンボルテーブルとグロブに関して理解していると思います。
#!/usr/bin/perl use strict; use warnigs; use Foo; test_method(); Package Foo; sub test_method { print 'hoge' } sub import { no strict 'refs'; *{ caller(). "::test_method"} = *test_method; } 1;
補足説明
今回紹介したコードを見ただけでは混乱する人しかいない*2と思いますので補足したいと思います。
次のようなコードをご覧ください
package main; use strict; use warnings; use lib 'lib'; use Foo; test_method(); # hoge warn *main::test_method; # *Foo::test_method
use Foo::Barには次の効用があります。
- Foo::Barにあるimportメソッドが実行されます。
- importメソッドではcallerが実行されます。
- callerが実行されると、呼び出し元の名前空間を取得します。
- この場合はmainです。連結して *main::test_methodに変化します。
- これはグロブです。
この*main::test_methodというグロブには自分自身がどこにいるかを調べるために、自分自身へのリファレンスを持っているのですが、その情報を*Foo::test_methodに置き換えているわけです。*3
実際にはグロブを丸ごと違うグロブを参照するような処理は行いません*4。グロブの一部(大抵はコードリファレンス)に対してだけこのような処理を行います。
まとめ
このグロブ割り当ての原理を利用したサブルーチンの記述は、CPANモジュールなどでよく見かける事があります。また社内ではこの記述がたくさんでてくるので新人向けに説明をする練習がてらに日記を書いてみました。
実際に社内勉強会をおこなって、文章が推敲されたらまた記事を書き直したいと思います。