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 can method 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:

    • can may 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_name on ::

    *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

Popular posts from this blog

java - Play! framework 2.0: How to display multiple image? -

gmail - Is there any documentation for read-only access to the Google Contacts API? -

php - Controller/JToolBar not working in Joomla 2.5 -