http://www.perlmonks.org?node_id=514356


in reply to How to sovle this, if i use strict i'm getting error.

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.

Replies are listed 'Best First'.
Re^2: How to sovle this, if i use strict i'm getting error.
by BUU (Prior) on Dec 06, 2005 at 09:10 UTC
    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.

      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.

      They think it's a bad idea because 'use strict' complains ... but if you know that what you're trying to do is correct, you can shut off 'use strict' for the specific complaint that it has:

      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.

        You don't actually need to change the current strictures:
        use strict; sub foo { print "Foo"; } sub bar { print "bar"; } main->can("foo")->();