オブジェクトは現在のパッケージのシンボルテーブルにどのようにアクセスしますか?

StackOverflow https://stackoverflow.com/questions/1822312

  •  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

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!
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top