CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Beginner:
Calling a subroutine whos name is stored as a scalar

 



perlFun
Novice

Aug 21, 2013, 3:15 PM

Post #1 of 10 (862 views)
Calling a subroutine whos name is stored as a scalar Can't Post

I have a program where essentially the user is passing over the cli a subroutine they will want called. Lets say this is stored as:

my $userSub = "sub_they_call({param1=>'p'})";

what I'm getting at here is it's the EXACT sub call, options and all.

Now, if I just have some simple subroutine in my .pl file and I do:

&$userSub;

This seems to work for me.


HOWEVER, the issue is, I have scenarios where the sub needed to be called is an instance method for a particular class. So for example I'll have a class, and an instance of that class, and need to call the sub. example:

my $modObj = MyFoo->new(); #made my object
#now MyFoo has a class called "get_it"
my $str = "get_it()";
#if I do the following I get a syntax error
$modObj->$str;

How is it that I can call the sub?

(By the way, I want to note this is a scenario where the subroutines is in the hundreds, possibly more, so I can't just store say a hash that has "directions" to call a certain sub based on certain string)


(This post was edited by perlFun on Aug 21, 2013, 3:17 PM)


FishMonger
Veteran / Moderator

Aug 21, 2013, 4:30 PM

Post #2 of 10 (857 views)
Re: [perlFun] Calling a subroutine whos name is stored as a scalar [In reply to] Can't Post


Quote
(By the way, I want to note this is a scenario where the subroutines is in the hundreds, possibly more, so I can't just store say a hash that has "directions" to call a certain sub based on certain string)


Actually, that's what you should be doing. It's called a dispatch table.
http://www.perlmonks.org/?node_id=456530
http://www.perlmonks.org/?node_id=902050

Another less desirable option would be to use string eval.
See: perldoc -f eval http://perldoc.perl.org/functions/eval.html


perlFun
Novice

Aug 21, 2013, 5:01 PM

Post #3 of 10 (854 views)
Re: [FishMonger] Calling a subroutine whos name is stored as a scalar [In reply to] Can't Post

I understand, but I'm sort of blocked from doing that in this case. I'm using some internal libraries my company owns that autogenerates these subroutines. There are potentially thousands of them and I don't even know what they all are.

about the eval, I'm not certain what to do with that. Are you saying if I put it in an eval it'll take away that syntax error I'm seeing and attempt to call the subroutine?


(This post was edited by perlFun on Aug 21, 2013, 5:03 PM)


FishMonger
Veteran / Moderator

Aug 21, 2013, 5:21 PM

Post #4 of 10 (850 views)
Re: [perlFun] Calling a subroutine whos name is stored as a scalar [In reply to] Can't Post


Quote
I'm using some internal libraries my company owns that autogenerates these subroutines. There are potentially thousands of them and I don't even know what they all are.


IMO, that indicates a very poor application design.

If the app autogenerates the subs, it could also add it to the dispatch table. When it needs to be executed, the app could first do a hash lookup to verify that the sub is available. If it is, then execute it, and if it isn't then a default error sub would be called.

Using eval to execute subs is fairly common, but I have not tested executing OO method calls. So, I can't say for sure if it will solve that part of your problem.


FishMonger
Veteran / Moderator

Aug 21, 2013, 5:26 PM

Post #5 of 10 (848 views)
Re: [perlFun] Calling a subroutine whos name is stored as a scalar [In reply to] Can't Post

Here's the results of a test I just made.


Code
#!/usr/bin/perl 

use strict;
use warnings;
use CGI;
use CGI::Pretty;

my $cgi = CGI->new;
my $title = 'test';
my $header = '$cgi->header, $cgi->start_html($title)';

print eval $header;


Output:

Code
D:\test>test.pl 
Content-Type: text/html; charset=ISO-8859-1

<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-US">
<head>
<title>test</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
</head>
<body>



perlFun
Novice

Aug 21, 2013, 5:35 PM

Post #6 of 10 (847 views)
Re: [FishMonger] Calling a subroutine whos name is stored as a scalar [In reply to] Can't Post


In Reply To

Quote
IMO, that indicates a very poor application design.


Unfortunately I don't have access to the code from these modules, nor do I have permissions to change them. There is no dispatch table available to list all the subroutines. To make things extra fun they randomly decide to add in new subs/take them out, without telling anyone. So it's very dynamic and mostly a guessing game.


I guess my issue is, this is the situation I have to deal with. People are going to pass me over the cli, subroutines they want called. I can get those subs as scalars, and then I need to call them. That's pretty much all I have to work with.


One other option I have is I could write a script to go in and grab their code myself and find what all subroutines are available and then populate the hash table myself, but I've got to be honest I'm worried that it will make the program really slow. In particular, it seems like I'd need to do that every time one of the objects I'm working with is instantiated. If instead I could just call the sub as it's passed on the cli rather than having to go in and populate a dispatch table every single time, it would be preferrable.

Yeah, when I put that in the eval, it still fails as a syntax error. I don't know maybe I've hit a roadblock.

EDIT: I see your post, so what you're doing is making the string the entire call, like $obj->sub(); . Ok, I see what I was doing wrong, I was just having the subroutine call itself as a string and calling that. I'll try it this way.

Thanks for all the help I've been really frustrated!


(This post was edited by perlFun on Aug 21, 2013, 5:37 PM)


perlFun
Novice

Aug 21, 2013, 6:54 PM

Post #7 of 10 (841 views)
Re: [perlFun] Calling a subroutine whos name is stored as a scalar [In reply to] Can't Post

You are a lifesaver! That works! Thank you!


perlFun
Novice

Aug 21, 2013, 7:08 PM

Post #8 of 10 (840 views)
Re: [perlFun] Calling a subroutine whos name is stored as a scalar [In reply to] Can't Post

Wait, actually I"m realizing now, I'm still blocked.


My problem is, I don't have access to the subroutine they're gonna call. If I run that example, it's true it executes. But my whole issue is I only have the scalar.

If I have for example:

$subCall (this holds the subcall, like set_name()) or something like that)

Now say I have my object, $person, which is of class Person. I want to call that set_name().

Now if I knew it was set_name() I wanted to do, I could do as you did and go:

my $callMethod = $person->set_name();

then I could go:

$callIt;

and it will call the subroutine. However, I don't know what method that scalar they're passing in contains.

Here's what I'm trying:


my $emp = Person->new(); #my my object
my $subCall = $emp->setFirstName("greg");
$subCall;
(this works, but here see I need to know what that sub is)

my $emp = Person->new();
#now say I have access to $callIt, which holds the value, setFirstName("greg"), but I don't know that, because it's just been passed in to me
my $subCall = $emp.'->'.$callIt;
$subCall;
#doesn't work, it just, well does nothing

my $emp = Person->new();
#again I have access to $callIt
my $subCall = $emp->$callIt;
$subCall;
#doesn't work, it tells me 'Can't locate method *the value of the string $callIt pass in* via package "Person"
(so for example if they passed in to me setFirstName("greg"); I have this stored as $callIt, this will say to me "Can't locate method setFirstName("greg") via package "Person"


perlFun
Novice

Aug 21, 2013, 7:39 PM

Post #9 of 10 (837 views)
Re: [perlFun] Calling a subroutine whos name is stored as a scalar [In reply to] Can't Post

I think I found the answer:
Make sure I have the options and the method name seperate

my $subCall = 'setFirstName';
my $op = 'GREG';
my $nameTwo = $emp->$subCall($op);
print "new 2 is $nameTwo\n";

This works!


FishMonger
Veteran / Moderator

Aug 21, 2013, 7:48 PM

Post #10 of 10 (837 views)
Re: [perlFun] Calling a subroutine whos name is stored as a scalar [In reply to] Can't Post

The more you say what you don't have access to and what you don't know what is being passed to you tells me that you don't have a legitimate reason to do this and that you're attempting to hack their app. I'm not going to be involved with this.

 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives