Let say I have one array that contains all subroutine name and I want to call all one by one.
foreach $sub (@arr){
print "Calling $sub\n";
#---How to call $sub?----
&$sub; ## will not work
}
Let say I have one array that contains all subroutine name and I want to call all one by one.
foreach $sub (@arr){
print "Calling $sub\n";
#---How to call $sub?----
&$sub; ## will not work
}
Your code is correct in general, but you need to turn off strict 'refs'
to make Perl allow you to use variable content as code refs.
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();
}
The output here is:
Calling foo
fooCalling bar
bar
I've also added parenthesis ()
after the call. That way we pass no arguments to %$sub
. If we do not those, the @_
argument list of the current subroutine will be used.
However, you should probably not do this. Especially if @arr
contains user input, this is a big problem. Your user can inject code. Consider this:
my @arr = qw/CORE::die/;
Now we get the following output:
Calling CORE::die
Died at /home/code/scratch.pl line 1492.
Oops. You don't want to do this. The die
example is not very bad, but like this you could easily call code in some different package that wasn't intended.
It's probably better to make a dispatch table. There is a whole chapter about those in Higher Order Perl by Mark Jason Dominus, which you can download for free on his website.
It basically means you put all the subs into a hash as code references, and then call those in your loop. That way you can control which ones are allowed.
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}->();
}
This outputs:
foobarbaz
wrong_entry is not allowed at /home/code/scratch.pl line 1494.
use strict
because there was no my sub
in the loop. In that case, the OP's code works. With strict
turned on however, strict 'refs'
needs to be disabled. –
Birkenhead You want to do that using code references.
foreach my $sub (@arr)
{
$sub->();
}
where @arr
contains scalars such as
my $rc = sub { print "Anonymous subroutine\n" };
or
sub func { print "Named sub\n" }
my $rc = \&func;
You can manipulate these scalars as you would any other, to form your array. However, it is more common and useful to use them as values in a hash, creating a dispatch table.
See perlref and perlsub, and (for example) this post and links in it for comments and details.
© 2022 - 2024 — McMap. All rights reserved.
(\&$name)->(@args)
– Glacialist