Perl日記

PerlとかRubyとかPHPとかPythonとか

AUTOLOADでメソッドを作ってるとcanで引っかからない

約2ヶ月前、can()はどのインスタンスでもできるんだよなーと思って、以下のコードを実行した。

use CGI;
my $q = CGI->new;
if ($q->can('header')) {
  print "CGI can 'header'.\n";
}
else {
  print "CGI can't 'header'.\n";
}

実行。

CGI can't 'header'.


あれーなんでtrueの方に行かないんだー?、と放置していたのが、今日ようやく分かったのでメモ。


CGI.pmのバージョンは「3.05」。
CGI.pmはもうどんなものがきても対応できるように書かれていて、その分読み込みコストも相当みたい。
それを軽くするために、メソッドの多くが実行時にAUTOLOADを通して作られていた。
can()は、いまあるメソッドから探してくるために、$q->can('header')だけでは、そんなメソッドありませんと言われたのだ。


だから、一回でもメソッドを使えば、can()はそれを見つけてくれる。

use CGI;
my $q = CGI->new;

$q->header; # void

if ($q->can('header')) {
  print "CGI can 'header'.\n";
}
else {
  print "CGI can't 'header'.\n";
}
CGI can 'header'.


ちなみに1。
sub AUTOLOAD で使われている _compile() が、実際に eval() でコードをランタイムで作っているようだけれど、それだけじゃなくて、やっぱり色々しているなーという印象。


ちなみに2。
最新のバージョン「3.49」でしか確認していないけれど、こちらでは最初からcan()が動いた。
オーバーライドされて、can()のときにも _compile() が起動されるようになっていた。