我保留了我想在运行时在名为$ action的变量中调用的子例程的名称.然后我用它在正确的时间调用该子:
&{\&{$action}}();
Run Code Online (Sandbox Code Playgroud)
工作良好.我唯一不喜欢的是它很丑,每次我这样做,我都感到很高兴为下一个开发者添加评论:
# call the sub by the name of $action
Run Code Online (Sandbox Code Playgroud)
有人知道更漂亮的方式吗?
更新:这里的想法是避免每次添加新的可调用子时都必须维护一个调度表,因为我是唯一的开发人员,我不担心其他程序员遵循或不遵循"规则".为了方便我牺牲了一点安全性.相反,我的调度模块将检查$ action以确保1)它是已定义子例程的名称而不是与eval一起运行的恶意代码,以及2)它不会运行任何以下划线开头的子,这将是通过此命名约定标记为仅限内部的subs.
有关这种方法的任何想法?发送表中的白名单子程序是我一直都会忘记的事情,我的客户宁愿我在"它工作"而不是"它是邪恶的安全"方面犯错误.(开发应用程序的时间非常有限)
最后更新:我想我毕竟已经决定了一个调度表.虽然我很好奇,如果读过这个问题的人曾经试图废除一个以及他们是如何做到的,那么我不得不向这里的集体智慧屈服.感谢所有,许多伟大的回应.
fri*_*edo 84
不是将子例程名称存储在变量中并调用它们,更好的方法是使用子例程引用的哈希(也称为分派表).
my %actions = ( foo => \&foo,
bar => \&bar,
baz => sub { print 'baz!' }
...
);
Run Code Online (Sandbox Code Playgroud)
然后你可以轻松地拨打正确的电话:
$actions{$action}->();
Run Code Online (Sandbox Code Playgroud)
您还可以添加一些检查以确保$action哈希中的有效密钥,等等.
一般来说,你应该避免使用符号引用(你现在正在做什么),因为它们会导致各种各样的问题.此外,使用实际子例程引用将与strict打开一起使用.
Har*_*men 21
只是&$action(),但通常从一开始就使用coderefs更好,或使用调度程序哈希.例如:
my $disp = {foo => \&some_sub, bar => \&some_other_sub };
$disp->{'foo'}->();
Run Code Online (Sandbox Code Playgroud)
mob*_*mob 16
咦?你可以说
$action->()
Run Code Online (Sandbox Code Playgroud)
例:
sub f { return 11 }
$action = 'f';
print $action->();
$ perl subfromscalar.pl
11
Run Code Online (Sandbox Code Playgroud)
像.这样的结构
'f'->() # equivalent to &f()
Run Code Online (Sandbox Code Playgroud)
也工作.
Tel*_*hus 11
我不确定我明白你的意思.(我认为这是最近一组"如何使用变量作为变量名?"的问题,但可能没有.)
在任何情况下,您都应该能够将整个子例程分配给变量(作为参考),然后直接调用它:
# create the $action variable - a reference to the subroutine
my $action = \&preach_it;
# later - perhaps much later - I call it
$action->();
sub preach_it {
print "Can I get an amen!\n"
}
Run Code Online (Sandbox Code Playgroud)
小智 10
最重要的是:为什么要将变量用作函数名.如果它是'eval'会发生什么?是否有可以使用的功能列表?或者它可以是任何功能?如果列表存在 - 它有多长?
通常,处理此类情况的最佳方法是使用调度表:
my %dispatch = (
'addition' => \&some_addition_function,
'multiplication' => sub { $self->call_method( @_ ) },
);
Run Code Online (Sandbox Code Playgroud)
然后就是:
$dispatch{ $your_variable }->( 'any', 'args' );
Run Code Online (Sandbox Code Playgroud)
__PACKAGE__->can($action)->(@args);
Run Code Online (Sandbox Code Playgroud)
有关can()的更多信息:http://perldoc.perl.org/UNIVERSAL.html
我做了类似的事情.我把它分成两行,使它更容易识别,但它并不是很漂亮.
my $sub = \&{$action};
$sub->();
Run Code Online (Sandbox Code Playgroud)
我不知道更正确或更漂亮的方式.对于它的价值,我们有生产代码可以完成您正在做的事情,并且无需禁用即可运行use strict.