如何在不使用eval的情况下动态包含Perl模块?

时间:2022-08-04 07:27:35

I need to dynamically include a Perl module, but if possible would like to stay away from eval due to work coding standards. This works:

我需要动态地包含一个Perl模块,但是如果可能的话,由于工作编码标准,我希望远离eval。这有效:

$module = "My::module";
eval("use $module;");

But I need a way to do it without eval if possible. All google searches lead to the eval method, but none in any other way.

但是如果可能的话,我需要一种没有eval的方法。所有谷歌搜索都会导致eval方法,但没有任何其他方式。

Is it possible to do it without eval?

没有评估可以做到吗?

6 个解决方案

#1


44  

Use require to load modules at runtime. It often a good idea to wrap this in a block (not string) eval in case the module can't be loaded.

使用require在运行时加载模块。如果无法加载模块,通常最好将其包装在一个块(而不是字符串)eval中。

eval {
    require My::Module;
    My::Module->import();
    1;
} or do {
   my $error = $@;
   # Module load failed. You could recover, try loading
   # an alternate module, die with $error...
   # whatever's appropriate
};

The reason for the eval {...} or do {...} syntax and making a copy of $@ is because $@ is a global variable that can be set by many different things. You want to grab the value as atomically as possible to avoid a race condition where something else has set it to a different value.

eval {...}或do {...}语法以及制作$ @的副本的原因是因为$ @是一个可以由许多不同的东西设置的全局变量。您希望尽可能原子地获取值,以避免竞争条件,其他东西已将其设置为不同的值。

If you don't know the name of the module until runtime you'll have to do the translation between module name (My::Module) and file name (My/Module.pm) manually:

如果您在运行时之前不知道模块的名称,则必须手动执行模块名称(My :: Module)和文件名(My / Module.pm)之间的转换:

my $module = 'My::Module';

eval {
    (my $file = $module) =~ s|::|/|g;
    require $file . '.pm';
    $module->import();
    1;
} or do {
    my $error = $@;
    # ...
};

#2


16  

How about using the core module Module::Load

如何使用核心模块Module :: Load

With your example:

用你的例子:

use Module::Load;
my $module = "My::module";
load $module;

"Module::Load - runtime require of both modules and files"

“Module :: Load - 运行时需要模块和文件”

"load eliminates the need to know whether you are trying to require either a file or a module."

“加载消除了你是否需要知道是否需要文件或模块的需要。”

If it fails it will die with something of the like "Can't locate xxx in @INC (@INC contains: ...".

如果它失败了它会死于类似“无法在@INC中找到xxx(@INC包含:......”)。

#3


10  

Well, there's always require as in

好吧,总是要求如此

require 'My/Module.pm';
My::Module->import();

Note that you lose whatever effects you may have gotten from the import being called at compile time instead of runtime.

请注意,在编译时调用导入而不是运行时,可能会丢失可能产生的任何影响。

Edit: The tradeoffs between this and the eval way are: eval lets you use the normal module syntax and gives you a more explicit error if the module name is invalid (as opposed to merely not found). OTOH, the eval way is (potentially) more subject to arbitrary code injection.

编辑:这与eval方式之间的权衡是:eval允许您使用普通模块语法,如果模块名称无效(而不是仅仅找不到),则会给出更明确的错误。 OTOH,eval方式(可能)更容易受到任意代码注入。

#4


4  

No, it's not possible to without eval, as require() needs the bareword module name, as described at perldoc -f require. However, it's not an evil use of eval, as it doesn't allow injection of arbitrary code (assuming you have control over the contents of the file you are requireing, of course).

不,没有eval是不可能的,因为require()需要裸字模块名称,如perldoc -f require所述。但是,它并不是eval的恶意用法,因为它不允许注入任意代码(假设您可以控制所需文件的内容,当然)。

EDIT: Code amended below, but I'm leaving the first version up for completeness.

编辑:下面修改了代码,但我要完成第一个版本。

I use I used to use this little sugar module to do dynamic loads at runtime:

我使用我曾经使用这个小糖模块在运行时进行动态加载:

package MyApp::Util::RequireClass;

use strict;
use warnings;

use Exporter 'import'; # gives you Exporter's import() method directly
our @EXPORT_OK = qw(requireClass);

# Usage: requireClass(moduleName);
# does not do imports (wrong scope) -- you should do this after calling me: $class->import(@imports);
sub requireClass
{
    my ($class) = @_;
    eval "require $class" or do { die "Ack, can't load $class: $@" };
}

1;

PS. I'm staring at this definition (I wrote it quite a while ago) and I'm pondering adding this: $class->export_to_level(1, undef, @imports);... it should work, but is not tested.

PS。我正在盯着这个定义(我很久以前写过)而且我正在考虑添加这个:$ class-> export_to_level(1,undef,@ import); ...它应该可以工作,但是没有经过测试。

EDIT: version 2 now, much nicer without an eval (thanks ysth): :)

编辑:现在版本2,没有评估更好(感谢ysth)::)

package MyApp::Util::RequireClass;

use strict;
use warnings;

use Exporter 'import'; # gives you Exporter's import() method directly
our @EXPORT_OK = qw(requireClass);

# Usage: requireClass(moduleName);
# does not do imports (wrong scope) -- you should do this after calling me: $class->import(@imports);
sub requireClass
{
    my ($class) = @_;

    (my $file = $class) =~ s|::|/|g;
    $file .= '.pm';
    require $file;  # will die if there was an error
}

1;

#5


1  

Class::MOP on CPAN has a load_class method for this: http://metacpan.org/pod/Class::MOP

CPAN上的Class :: MOP有一个load_class方法:http://metacpan.org/pod/Class :: Male

#6


0  

i like doing things like..

我喜欢做像......

require Win32::Console::ANSI if ( $^O eq "MSWin32" );

需要Win32 :: Console :: ANSI if($ ^ O eq“MSWin32”);

#1


44  

Use require to load modules at runtime. It often a good idea to wrap this in a block (not string) eval in case the module can't be loaded.

使用require在运行时加载模块。如果无法加载模块,通常最好将其包装在一个块(而不是字符串)eval中。

eval {
    require My::Module;
    My::Module->import();
    1;
} or do {
   my $error = $@;
   # Module load failed. You could recover, try loading
   # an alternate module, die with $error...
   # whatever's appropriate
};

The reason for the eval {...} or do {...} syntax and making a copy of $@ is because $@ is a global variable that can be set by many different things. You want to grab the value as atomically as possible to avoid a race condition where something else has set it to a different value.

eval {...}或do {...}语法以及制作$ @的副本的原因是因为$ @是一个可以由许多不同的东西设置的全局变量。您希望尽可能原子地获取值,以避免竞争条件,其他东西已将其设置为不同的值。

If you don't know the name of the module until runtime you'll have to do the translation between module name (My::Module) and file name (My/Module.pm) manually:

如果您在运行时之前不知道模块的名称,则必须手动执行模块名称(My :: Module)和文件名(My / Module.pm)之间的转换:

my $module = 'My::Module';

eval {
    (my $file = $module) =~ s|::|/|g;
    require $file . '.pm';
    $module->import();
    1;
} or do {
    my $error = $@;
    # ...
};

#2


16  

How about using the core module Module::Load

如何使用核心模块Module :: Load

With your example:

用你的例子:

use Module::Load;
my $module = "My::module";
load $module;

"Module::Load - runtime require of both modules and files"

“Module :: Load - 运行时需要模块和文件”

"load eliminates the need to know whether you are trying to require either a file or a module."

“加载消除了你是否需要知道是否需要文件或模块的需要。”

If it fails it will die with something of the like "Can't locate xxx in @INC (@INC contains: ...".

如果它失败了它会死于类似“无法在@INC中找到xxx(@INC包含:......”)。

#3


10  

Well, there's always require as in

好吧,总是要求如此

require 'My/Module.pm';
My::Module->import();

Note that you lose whatever effects you may have gotten from the import being called at compile time instead of runtime.

请注意,在编译时调用导入而不是运行时,可能会丢失可能产生的任何影响。

Edit: The tradeoffs between this and the eval way are: eval lets you use the normal module syntax and gives you a more explicit error if the module name is invalid (as opposed to merely not found). OTOH, the eval way is (potentially) more subject to arbitrary code injection.

编辑:这与eval方式之间的权衡是:eval允许您使用普通模块语法,如果模块名称无效(而不是仅仅找不到),则会给出更明确的错误。 OTOH,eval方式(可能)更容易受到任意代码注入。

#4


4  

No, it's not possible to without eval, as require() needs the bareword module name, as described at perldoc -f require. However, it's not an evil use of eval, as it doesn't allow injection of arbitrary code (assuming you have control over the contents of the file you are requireing, of course).

不,没有eval是不可能的,因为require()需要裸字模块名称,如perldoc -f require所述。但是,它并不是eval的恶意用法,因为它不允许注入任意代码(假设您可以控制所需文件的内容,当然)。

EDIT: Code amended below, but I'm leaving the first version up for completeness.

编辑:下面修改了代码,但我要完成第一个版本。

I use I used to use this little sugar module to do dynamic loads at runtime:

我使用我曾经使用这个小糖模块在运行时进行动态加载:

package MyApp::Util::RequireClass;

use strict;
use warnings;

use Exporter 'import'; # gives you Exporter's import() method directly
our @EXPORT_OK = qw(requireClass);

# Usage: requireClass(moduleName);
# does not do imports (wrong scope) -- you should do this after calling me: $class->import(@imports);
sub requireClass
{
    my ($class) = @_;
    eval "require $class" or do { die "Ack, can't load $class: $@" };
}

1;

PS. I'm staring at this definition (I wrote it quite a while ago) and I'm pondering adding this: $class->export_to_level(1, undef, @imports);... it should work, but is not tested.

PS。我正在盯着这个定义(我很久以前写过)而且我正在考虑添加这个:$ class-> export_to_level(1,undef,@ import); ...它应该可以工作,但是没有经过测试。

EDIT: version 2 now, much nicer without an eval (thanks ysth): :)

编辑:现在版本2,没有评估更好(感谢ysth)::)

package MyApp::Util::RequireClass;

use strict;
use warnings;

use Exporter 'import'; # gives you Exporter's import() method directly
our @EXPORT_OK = qw(requireClass);

# Usage: requireClass(moduleName);
# does not do imports (wrong scope) -- you should do this after calling me: $class->import(@imports);
sub requireClass
{
    my ($class) = @_;

    (my $file = $class) =~ s|::|/|g;
    $file .= '.pm';
    require $file;  # will die if there was an error
}

1;

#5


1  

Class::MOP on CPAN has a load_class method for this: http://metacpan.org/pod/Class::MOP

CPAN上的Class :: MOP有一个load_class方法:http://metacpan.org/pod/Class :: Male

#6


0  

i like doing things like..

我喜欢做像......

require Win32::Console::ANSI if ( $^O eq "MSWin32" );

需要Win32 :: Console :: ANSI if($ ^ O eq“MSWin32”);