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
可以由封裝覆蓋,或從它繼承的任何類。
- 定義方法的包可能與調用者不同。
這實際上可能是您正在尋找的行爲。
另一種方法是使用稱爲symbolic reference的東西。
{
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');
(該Pure Perl版本的Package::Stash使用符號引用,而不是藏匿)
它甚至可能使例程/方法的別名,彷彿已經從進口一個正在使用的模塊Exporter:
*echo = \&{$package_name.'::echo'};
echo('Hello World');
我會r ecommend限制別名的範圍,但:
{
local *echo = \&{$package_name.'::echo'};
echo('Hello World');
}
這是一個例外,在那裏你可以使用啓用strict 'refs'
一個象徵性的參考。
如果你不想傳遞一個invocant,那麼你想要的不是調用*方法*。 – hobbs
@hobbs:謝謝。我已經更新了該問題以使用更正確的術語。 – Sam