Re: How to sovle this, if i use strict i'm getting error.
by Corion (Patriarch) on Dec 06, 2005 at 07:22 UTC
|
Using a string as a subroutine name is almost always a bad idea. What you want instead is a "dispatch table", that is, a hash that maps your names to subroutines:
#!/usr/local/bin/perl -w
use strict;
sub test1 {
print 'test1';
}
sub test2 {
print 'test2';
}
for my $i (1,2) {
my $name = "test$i";
if (exists $handler{$name}) {
$handler{$name}->();
} else {
warn "Don't know what to do with '$name'";
};
};
my %handler = (
test1 => \&test1,
test2 => \&test2,
);
This method allows you to extend your program while also giving you good error handling in the case that you want to call something by name which doesn't exist. It also makes your program more secure because only things can be called that you have specified as callable. | [reply] [d/l] |
|
|
I suppose I'm nitpicking here, but something has always bothered me about this answer (and those like it). Perl already provides a perfectly code "dispatch table", that is, a hash that maps subroutine names to subroutine references! I'm not sure why people are so strongly discouarged from using it. It's one thing to discourage accessing this hash for variables, since that leads to global variables and other such evil, but in this case you're just wasting effort to create something that already exists.
| [reply] |
|
|
The point is control. Eval-based dispatch is much like an unstructured goto $EXPR - you cannot really be sure of the program flow. An explicit hash lists all locations where the code is allowed to branch to. This prevents malicious attacks where the attacker could try to make a call to the exit or system core function and it allows much better error handling. It also decouples the subroutine name from the argument, which I find very convenient in web applications.
| [reply] [d/l] [select] |
|
|
| [reply] |
|
|
use strict;
use warnings;
for my $i ( 1 .. 2 ) {
$a = 'test'.$i;
no strict 'refs';
&$a;
}
sub test1 { print 'test1'; }
sub test2 { print 'test2'; }
So where's the problem with that? None, really. I mean, it doesn't propogate, so you're still protected in the subroutine you're calling:
use strict;
use warnings;
for my $a qw( test1 test2 ) {
no strict 'refs';
&$a;
}
sub test1 { print 'test1'; }
sub test2 { my $x='test3'; &$x }
PS. For the original poster -- it's convention that you don't use $a and $b as variable names, unless you're dealing with sorting. | [reply] [d/l] [select] |
|
|
Re: How to sovle this, if i use strict i'm getting error.
by gopalr (Priest) on Dec 06, 2005 at 08:42 UTC
|
| [reply] |
Re: How to sovle this, if i use strict i'm getting error.
by Samy_rio (Vicar) on Dec 06, 2005 at 07:15 UTC
|
#!/usr/local/bin/perl
use strict;
for(my $i=1; $i<=2; $i++) {
my $a = 'test'.$i;
eval "&$a";
}
sub test1 {
print 'test1';
}
sub test2 {
print 'test2';
}
Regards, Velusamy R. eval"print uc\"\\c$_\""for split'','j)@,/6%@0%2,`e@3!-9v2)/@|6%,53!-9@2~j';
| [reply] [d/l] [select] |
|
|
To sum up all that has been said, especially the warning re avoiding symrefs if possible, and here it is not only possible but also highly recommendable, so I'm stressing the point once more:
#!/usr/bin/perl -l
use strict;
use warnings;
my %dispatch=(
test1 => sub {
print 'test1';
},
test2 => sub {
print 'test2';
} );
for(1,2) {
$dispatch{"test$_"}->();
}
__END__
Notice that I also used -> rather than & for dereferencing, which is preferrable for various reasons, and a (more) perlish for loop, which could have also been a modifier:
$dispatch{"test$_"}->() for 1,2;
But then, if you just need a few numbered subs, depending on your actual application, you may prefer an array instead:
#!/usr/bin/perl -l
use strict;
use warnings;
my @test=( sub { print 'test0' }, sub { print 'test1' } );
$test[$_]->() for 0,1;
# or even
$_->() for @test;
__END__
| [reply] [d/l] [select] |
Re: How to sovle this, if i use strict i'm getting error.
by gube (Parson) on Dec 06, 2005 at 07:16 UTC
|
Hi sen, put eval "&$a"; and run the code than it will works..
Refer perldoc -f eval
| [reply] [d/l] |