オブジェクトは現在のパッケージのシンボルテーブルにどのようにアクセスしますか?
-
10-07-2019 - |
質問
オブジェクトがインスタンス化された現在のパッケージのシンボルテーブルにアクセスするにはどうすればよいですか?たとえば、次のようなものがあります:
my $object = MyModule->new;
# this looks in the current package, to see if there's a function named run_me
# I'd like to know how to do this without passing a sub reference
$object->do_your_job;
do_your_job
の実装で __ PACKAGE __
を使用する場合、 MyModule
パッケージを検索します。適切なパッケージでどのように見えるようにできますか?
編集:これを明確にするようにします。次のコードがあるとします:
package MyMod;
sub new {
return bless {},オブジェクトがインスタンス化された現在のパッケージのシンボルテーブルにアクセスするにはどうすればよいですか?たとえば、次のようなものがあります:
my $object = MyModule->new;
# this looks in the current package, to see if there's a function named run_me
# I'd like to know how to do this without passing a sub reference
$object->do_your_job;
do_your_job
の実装で __ PACKAGE __
を使用する場合、 MyModule
パッケージを検索します。適切なパッケージでどのように見えるようにできますか?
編集:これを明確にするようにします。次のコードがあるとします:
<*>
今、 $ x
は main
が現在のパッケージであることに気づき、そのシンボルテーブルを検索します。 Scalar :: Util
のblessedを使用してみましたが、 main
の代わりに MyModule
を使用できました。うまくいけば、これが少し明確になりました。
[0]
}
sub do_your_job {
my $self = shift;
# of course find_package_of is fictional here
# just for this example's sake, $pkg should be main
my $pkg = find_package_of($self);
if(defined &{ $pkg . '::run_me' }) {
# the function exists, call it.
}
}
package main;
sub run_me {
print "x should run me.\n";
}
my $x = MyMod->new;
# this should find the run_me sub in the current package and invoke it.
$x->do_your_job;
今、 $ x
は main
が現在のパッケージであることに気づき、そのシンボルテーブルを検索します。 Scalar :: Util
のblessedを使用してみましたが、 main
の代わりに MyModule
を使用できました。うまくいけば、これが少し明確になりました。
解決
caller
は、呼び出し元のパッケージを示します。 (ここで標準perlを追加しました。)
use Symbol qw<qualify_to_ref>;
#...
my $pkg = caller;
my $symb = qualify_to_ref( 'run_me', $pkg );
my $run_me = *{$symb}{CODE};
$run_me->() if defined $run_me;
それを調べて定義されているかどうかを確認し、標準のperlはCommon Subexpression Eliminationを行わないのでそれを呼び出すために調べるため、1)を取得し、2)の定義をチェックすることもできますスロット、および3)定義されている場合は実行します。
今、あるパッケージでオブジェクトを作成し、別のパッケージで使用する場合、それはあまり助けにはなりません。おそらくコンストラクタに 'owning_package'
のような追加フィールドを追加する必要があるでしょう。
package MyMod;
#...
sub new {
#...
$self->{owning_package} = caller || 'main';
#...
}
Now $ x-&gt; {owning_package}
には 'main'
が含まれます。
他のヒント
perldoc -f caller を参照してください:
#!/usr/bin/perl
package A;
use strict; use warnings;
sub do_your_job {
my ($self) = @_;
my ($pkg) = caller;
if ( my $sub = $pkg->can('run_me') ) {
$sub->();
}
}
package B;
use strict; use warnings;
sub test {
A->do_your_job;
}
sub run_me {
print "No, you can't!\n";
}
package main;
use strict; use warnings;
B->test;
出力:
C:\Temp> h No, you can't!