Perl phương pháp gọi là chương trình con chỉ thông thường, có được invocant như giá trị đầu tiên.
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)
Nếu bạn muốn gọi một chương trình con mà không có một invocant, bạn sẽ cần phải gọi nó là khác nhau.
{
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');
Phương pháp can
trả về một tham chiếu đến các chương trình con đó sẽ được gọi nếu nó đã được kêu gọi invocant. Các coderef sau đó có thể được sử dụng một cách riêng biệt.
my $code_ref = $package_name->can('echo');
$code_ref->('Hello World');
Có một số hãy cẩn thận khi sử dụng can
:
can
có thể được ghi đè bởi các gói, hoặc bất kỳ lớp mà từ đó nó được thừa hưởng.
- Gói định nghĩa phương thức có thể khác với trình kích hoạt.
Đây thực sự là hành vi bạn đang tìm kiếm.
Cách tiếp cận khác là sử dụng thứ được gọi là symbolic reference.
{
no strict 'refs';
&{ $package_name.'::echo' }('Hello World');
}
Không nên sử dụng tham chiếu tượng trưng. Một phần của vấn đề là có thể vô tình sử dụng một tham chiếu tượng trưng mà bạn không có ý định sử dụng nó. Đây là lý do tại sao bạn không thể có hiệu lực use strict 'refs';
.
Đây có thể là cách đơn giản nhất để thực hiện những gì bạn muốn làm.
Nếu bạn không muốn sử dụng tham chiếu tượng trưng, bạn có thể sử dụng 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');
Vấn đề duy nhất với điều này là bạn sẽ phải chia $package_name
trên ::
*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');
Đây không phải là lớn của một vấn đề mặc dù. Sau khi xem nhanh trên CPAN bạn tìm thấy Package::Stash.
use Package::Stash;
my $stash = Package::Stash->new($package_name);
my $coderef = $stash->get_symbol('&echo');
$coderef->('Hello World');
(Phiên bản Pure Perl của Package::Stash sử dụng tài liệu tham khảo mang tính biểu tượng, không phải là Stash)
Nó thậm chí có thể làm cho một bí danh của chương trình con/phương pháp, như thể đã được nhập khẩu từ một mô-đun đang sử dụng Exporter:
*echo = \&{$package_name.'::echo'};
echo('Hello World');
Tôi sẽ ecommend giới hạn phạm vi của bí danh mặc dù:
{
local *echo = \&{$package_name.'::echo'};
echo('Hello World');
}
Đây là một ngoại lệ, nơi bạn có thể sử dụng một tài liệu tham khảo mang tính biểu tượng với strict 'refs'
kích hoạt.
Nguồn
2012-06-05 02:40:14
Nếu bạn không muốn truyền một kẻ xâm lược, thì những gì bạn muốn không phải là gọi phương thức *. – hobbs
@hobbs: Cảm ơn. Tôi đã cập nhật câu hỏi để sử dụng thuật ngữ chính xác hơn. – Sam