Perlメソッド呼び出しは単なる通常のサブルーチンであり、最初の値として呼び出し元を取得します。
use strict;
use warnings;
use 5.10.1;
{
package MyPackage;
sub new{ bless {}, shift } # overly simplistic constructor (DO NOT REUSE)
sub echo{ say @_ }
}
my $package_name = 'MyPackage';
$package_name->echo;
my $object = $package_name->new();
$object->echo; # effectively the same as MyPackage::echo($object)
MyPackage
MyPackage=HASH(0x1e2a070)
呼び出し元なしでサブルーチンを呼び出したい場合は、別の方法で呼び出す必要があります。
{
no strict 'refs';
${$package_name.'::'}{echo}->('Hello World');
&{$package_name.'::echo'}('Hello World');
}
# only works for packages without :: in the name
$::{$package_name.'::'}{echo}->('Hello World');
$package_name->can('echo')->('Hello World');
このcan
メソッドは、呼び出し元で呼び出された場合に呼び出されるサブルーチンへの参照を返します。その後、coderefを個別に使用できます。
my $code_ref = $package_name->can('echo');
$code_ref->('Hello World');
使用する際の注意点がいくつかありますcan
:
can
パッケージ、またはパッケージが継承する任意のクラスによってオーバーライドされる場合があります。
- メソッドを定義するパッケージは、呼び出し元とは異なる場合があります。
これは実際にはあなたが探している振る舞いかもしれません。
別のアプローチは、シンボリックリファレンスと呼ばれるものを使用することです。
{
no strict 'refs';
&{ $package_name.'::echo' }('Hello World');
}
通常、シンボリック参照の使用はお勧めしません。問題の一部は、シンボル参照を使用するつもりがなかった場所で誤って使用する可能性があることです。これがuse strict 'refs';
、効果を発揮できない理由です。
これはあなたがやりたいことをする最も簡単な方法かもしれません。
シンボリック参照を使用したくない場合は、Stashを使用できます。
$MyPackage::{echo}->('Hello World');
$::{'MyPackage::'}{echo}->('Hello World');
$main::{'MyPackage::'}{echo}->('Hello World');
$main::{'main::'}{'MyPackage::'}{echo}->('Hello World');
$main::{'main::'}{'main::'}{'main::'}{'MyPackage::'}{echo}->('Hello World');
これに関する唯一の問題は、分割する必要があるということ$package_name
です::
*Some::Long::Package::Name::echo = \&MyPackage::echo;
$::{'Some::'}{'Long::'}{'Package::'}{'Name::'}{echo}('Hello World');
sub get_package_stash{
my $package = shift.'::';
my @package = split /(?<=::)/, $package;
my $stash = \%:: ;
$stash = $stash->{$_} for @package;
return $stash;
}
get_package_stash('Some::Long::Package::Name')->{echo}('Hello World');
しかし、これはそれほど大きな問題ではありません。CPANをざっと見てみると、 Package::Stashが見つかります。
use Package::Stash;
my $stash = Package::Stash->new($package_name);
my $coderef = $stash->get_symbol('&echo');
$coderef->('Hello World');
(PurePerlバージョンのPackage:: Stashは、Stashではなくシンボリック参照を使用します)
Exporterを使用していたモジュールからインポートされたかのように、サブルーチン/メソッドのエイリアスを作成することも可能です。
*echo = \&{$package_name.'::echo'};
echo('Hello World');
ただし、エイリアスの範囲を制限することをお勧めします。
{
local *echo = \&{$package_name.'::echo'};
echo('Hello World');
}
これは例外であり、strict 'refs'
有効にした状態でシンボリック参照を使用できます。