How do you call a subroutine from a package, given the package name in Perl?
methods, package, perl, reflection
Solution
Perl method calls are just regular subroutines, which get the invocant as the first value.
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)
If you want to call a subroutine without an invocant, you will need to call it differently.
{
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');
The `can` method returns a reference to the subroutine that would be called if it had been called on the invocant. The coderef can then be used separately.
my $code_ref = $package_name->can('echo');
$code_ref->('Hello World');
There are some caveats to using `can`:
- `can` may be overridden by the package, or any class from which it inherits.
- The package that defines a method may be different than the invocant.
This may actually be the behaviour you're looking for though.
Another approach is to use something called a symbolic reference.
{
no strict 'refs';
&{ $package_name.'::echo' }('Hello World');
}
Using symbolic references is usually not recommended. Part of the problem is that it is possible to accidently use a symbolic reference where you didn't intend on using one. This is why you can't have `use strict 'refs';` in effect.
This may be the simplest way to do what you want to do though.
If you don't want to use a symbolic reference you could use the 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');
The only problem with this is that you would have to split `$package_name` on `::`
*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');
This isn't that big of a problem though. After a quick look on CPAN you find Package::Stash.
use Package::Stash;
my $stash = Package::Stash->new($package_name);
my $coderef = $stash->get_symbol('&echo');
$coderef->('Hello World');
(The Pure Perl version of Package::Stash uses symbolic references, not the Stash)
It's even possible to make an alias of the subroutine/method, as if had been imported from a module that was using Exporter:
*echo = \&{$package_name.'::echo'};
echo('Hello World');
I would recommend limiting the scope of the alias though:
{
local *echo = \&{$package_name.'::echo'};
echo('Hello World');
}
This is an exception, where you can use a symbolic reference with `strict 'refs'` enabled.
Problem
Given a variable containing a string that represents the name of a package, how do I call a specific subroutine of the package? Here's the closest thing I have figured out: ``` package MyPackage; sub echo { print shift; } my $package_name = 'MyPackage'; $package_name->echo('Hello World'); 1; ``` The problem with this code is the subroutine is called as a class method; the package name is passed in as the first argument. I want to invoke the subroutine from the package name without a special first argument being implicitly passed in.