参见英文答案 >
How can I elegantly call a Perl subroutine whose name is held in a variable? 12个
假设我有一个包含所有子程序名称的数组,我想逐个调用.
假设我有一个包含所有子程序名称的数组,我想逐个调用.
foreach $sub (@arr){ print "Calling $sub\n"; #---How to call $sub?---- &$sub; ## will not work }
解决方法
您的代码一般是正确的,但您需要关闭
strict 'refs'
以使Perl允许您使用变量内容作为代码引用.
use strict; use warnings; sub foo { print "foo" } sub bar { print "bar" } my @arr = qw/foo bar/; foreach my $sub (@arr) { no strict 'refs'; print "Calling $sub\n"; &$sub(); }
这里的输出是:
Calling foo fooCalling bar bar
我在调用后还添加了括号().这样我们就不会向%$sub传递任何参数.如果我们不这样做,将使用当前子例程的@_参数列表.
但是,你可能不应该这样做.特别是如果@arr包含用户输入,这是一个大问题.您的用户可以注入代码.考虑一下:
my @arr = qw/CORE::die/;
现在我们得到以下输出:
Calling CORE::die Died at /home/code/scratch.pl line 1492.
哎呀.你不想这样做.模具示例并不是很糟糕,但是像这样你可以很容易地在一些不合适的包中调用代码.
制作一个dispatch table可能更好.有一整章关于Mark Jason Dominus的高阶Perl,你可以download for free on his website.
它基本上意味着您将所有subs作为代码引用放入哈希,然后在循环中调用它们.这样你就可以控制哪些是允许的.
use strict; use warnings; sub baz { print "baz" } my %dispatch = ( foo => sub { print "foo" },bar => sub { print "bar" },baz => \&baz,); my @arr = qw/foo bar baz wrong_entry/; foreach my $sub ( @arr ) { die "$sub is not allowed" unless exists $dispatch{$sub}; $dispatch{$sub}->(); }
这输出:
foobarbaz wrong_entry is not allowed at /home/code/scratch.pl line 1494.