Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

variable subroutine call

by davg (Initiate)
on Dec 12, 2007 at 01:06 UTC ( [id://656526]=perlquestion: print w/replies, xml ) Need Help??

davg has asked for the wisdom of the Perl Monks concerning the following question:

How can I (is there a way to...) call a subroutine using a variable. For example, A user provides the name of a subroutine in a perl module, maybe as <STDIN>. The perl script has to run that subroutine. But of course, the name of that subroutine is stored in a scalar.
package ECHO_MODULE; use Exporter (); @ISA = qw(Exporter); @EXPORT = qw($say_hi $say_bye); sub say_hi {print "hi\n";} sub say_bye {print "bye\n"}

----------------------- print "enter subroutine name: "; $subname = <STDIN>; $subname() ????

(see what I'm getting after?)

Replies are listed 'Best First'.
Re: variable subroutine call
by meraxes (Friar) on Dec 12, 2007 at 01:15 UTC

    In a word: yup.

    #!/usr/bin/perl use strict; use warnings; sub say_whoops { print "whoops\n"; } my %functions = ( 'hi' => sub {print "hi\n";}, 'bye' => sub {print "bye\n";}, 'whoops' => \&say_whoops, ); foreach my $key ( keys %functions ) { $functions{$key}(); }

    The "hi" and "bye" are anonymous subroutines whereas whoops is executing via a reference to say_whoops(). I've stored the references in a hash simply because it's quick and easy though there are other ways. You can even pass them arguments! Take a look at perlsub for all the specifics.

    HOWEVER, it's exceedingly dangerous to take arguments from STDIN to run a routine unless ya know where they're coming from. Potential security hazard. Striken as per shmem's comment. Guess I'm a worry wart really.

    --
    meraxes
      HOWEVER, it's exceedingly dangerous to take arguments from STDIN to run a routine unless ya know where they're coming from. Potential security hazard.

      Care to elaborate a bit? I am running it, and it is my input, so I know where it is coming from: from me. And if I am not trustworthy for myself, who is?

      What you say only applies (sometimes) when the program is running on behalf of somebody else (e.g. setuid).

      --shmem

      _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                    /\_¯/(q    /
      ----------------------------  \__(m.====·.(_("always off the crowd"))."·
      ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}

        Sorry. I guess I should have said it can be dangerous if others have access to it. Perhaps my own prejudices. I tend to be wary of things that execute code (or in this case, arbitrary subroutines) without any checking of the input other than "does the function exist". That's all.

        --
        meraxes
        I am running it, and it is my input, so I know where it is coming from: from me. And if I am not trustworthy for myself, who is?
        That sums up the situation nicely. Often times it is precisely because I am running it and it is my input that problems occur. I'm the last person I would trust.

        I'm with meraxes on this one but of course ymmv. :-)

Re: variable subroutine call
by pfaut (Priest) on Dec 12, 2007 at 01:24 UTC

    You can use a variable containing the name of a function as a reference to call the function.

    sub say { print $_[0],$/ }; $x = 'say'; $x->('hello');

    Although Perl supports this, you shouldn't use it because it can be very dangerous. This is disallowed when 'use strict refs' is in effect. meraxes solution is better. Store references to allowed functions in a hash and allow the user to choose a function by entering its key value.

    90% of every Perl application is already written.
    dragonchild
Re: variable subroutine call
by shmem (Chancellor) on Dec 12, 2007 at 01:17 UTC
    Calling a sub resolved from a scalar read from STDIN, fixing your code a bit:
    package ECHO_MODULE; sub say_hi {print "hi\n";} sub say_bye {print "bye\n"} package main; print "enter subroutine name: "; chop ($subname = <STDIN>); if (ECHO_MODULE->can($subname) ) { ECHO_MODULE->$subname(); } else { print "sub '$subname' not defined.\n"; }

    Read the perl documentation, namely perlrun, perlsub, perlref... anything, all, more.

    update, as per privmsg from memnoch:

    For the can() method, see perlobj: it resides in the module UNIVERSAL from which all classes implicitly inherit as their last base class. As chromatic pointed out below, the method can() returns a subroutine reference for its argument, and calling a sub as method or function makes a difference. ECHO_MODULE->$subname() will get ECHO_MODULE as its first argument, while ECHO_MODULE->can($subname)->() will not. It all depends on the design of the package - is it a functional package (a.k.a library) or a class?

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}

      I think this is much clearer as:

      if (my $sub_ref = ECHO_MODULE->can($subname) ) { $sub_ref->(); } ...

      Be careful mixing up methods and functions.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://656526]
Approved by lidden
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (3)
As of 2024-04-26 07:25 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found