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.

Original source