reflection - How do you call a subroutine from a package, given the package name in Perl? -
given variable containing string represents name of package, how call specific subroutine of package?
here's closest thing have figured out:
package mypackage; sub echo { print shift; } $package_name = 'mypackage'; $package_name->echo('hello world'); 1; the problem code subroutine called class method; package name passed in first argument. want invoke subroutine package name without special first argument being implicitly passed in.
perl method calls regular subroutines, invocant first value.
use strict; use warnings; use 5.10.1; { package mypackage; sub new{ bless {}, shift } # overly simplistic constructor (do not reuse) sub echo{ @_ } } $package_name = 'mypackage'; $package_name->echo; $object = $package_name->new(); $object->echo; # same mypackage::echo($object) mypackage mypackage=hash(0x1e2a070) if want call subroutine without invocant, need call differently.
{ no strict 'refs'; ${$package_name.'::'}{echo}->('hello world'); &{$package_name.'::echo'}('hello world'); } # works packages without :: in name $::{$package_name.'::'}{echo}->('hello world'); $package_name->can('echo')->('hello world'); the
canmethod returns reference subroutine called if had been called on invocant. coderef can used separately.my $code_ref = $package_name->can('echo'); $code_ref->('hello world');there caveats using
can:canmay overridden package, or class inherits.- the package defines method may different invocant.
may behaviour you're looking though.another approach use called symbolic reference.
{ no strict 'refs'; &{ $package_name.'::echo' }('hello world'); }using symbolic references not recommended. part of problem is possible accidently use symbolic reference didn't intend on using one. why can't have
use strict 'refs';in effect.this may simplest way want though.
if don't want use symbolic reference use 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 problem have split
$package_nameon::*some::long::package::name::echo = \&mypackage::echo; $::{'some::'}{'long::'}{'package::'}{'name::'}{echo}('hello world'); sub get_package_stash{ $package = shift.'::'; @package = split /(?<=::)/, $package; $stash = \%:: ; $stash = $stash->{$_} @package; return $stash; } get_package_stash('some::long::package::name')->{echo}('hello world');this isn't big of problem though. after quick on cpan find package::stash.
use package::stash; $stash = package::stash->new($package_name); $coderef = $stash->get_symbol('&echo'); $coderef->('hello world');(the pure perl version of package::stash uses symbolic references, not stash)
it's possible make alias of subroutine/method, if had been imported module using exporter:
*echo = \&{$package_name.'::echo'}; echo('hello world'); i recommend limiting scope of alias though:
{ local *echo = \&{$package_name.'::echo'}; echo('hello world'); } this exception, can use symbolic reference strict 'refs' enabled.
Comments
Post a Comment