7

Let's say I have a perl module file and I want to include and use it dynamically at runtime. Said module includes a class that I need to instantiate without knowing its name until runtime.

For example,

#inside module.pm

package module;

sub new {
#setup object
}

#inside main.pl

#get module.pm as argument
my $module_var = #load reference to module using text argument?
my $module_instance = $module_var->new();
Mike
  • 58,961
  • 76
  • 175
  • 221
  • 5
    A better more modern idea would make a base class, and factor off these dynamically loaded entities as `MooseX::Traits`, then you just instantiate the baseclass with said traits `BaseClass->with_traits('Foobar::Baz')->new;` – Evan Carroll Aug 12 '10 at 18:46

3 Answers3

11

This can be done without eval as follows:

my $module_name = 'Some::Module';

(my $require_name = $module_name . ".pm") =~ s{::}{/}g;

require $require_name;

my $obj = $module_name->new();

If you need to do this many times, just wrap up that code in a subroutine:

sub load_module {
    for (@_) {
        (my $file = "$_.pm") =~ s{::}{/}g;
        require $file;
    }
}

load_module 'Some::Module', 'Another::Module';
Eric Strom
  • 39,821
  • 2
  • 80
  • 152
7
my $module_var = 'module';
eval "use $module_var; 1" or die $@;
my $module_instance = $module_var->new();

Note that the eval is a possible security hole. If $module_var contains code, it will get executed. One way around this is to use Class::MOP. Replace the eval line with:

use Class::MOP;
Class::MOP::load_class($module_var);

If you don't want to require Class::MOP, you could copy the _is_valid_class_name function from it into your code, and just make sure that $module_var contains a valid class before you eval it. (Note that if you're using Moose, you're already using Class::MOP behind-the-scenes.)

cjm
  • 61,471
  • 9
  • 126
  • 175
  • is there a safer way than eval? security is a concern for me – Mike Aug 12 '10 at 18:25
  • 1
    `Class::MOP::load_class()` being deprecated, it's possible to find [the same utility in `Class::Load`](https://metacpan.org/pod/Class::Load). – smonff Nov 17 '22 at 15:34
1

You can do this with eval.

my $module = "Foo";
eval "use $module;1" or die($@); # Couldn't load module
szbalint
  • 1,643
  • 12
  • 20