4

I'm facing an issue using eval function.

Indeed I have some function name inside a SQL database, my goal is to execute those functions within perl (after retrieve in SQL).

Here is what I'm doing, considering that $RssSource->{$k}{Proceed} contains "&test" as a string retrieved from SQL:

my $str2 = "ABCD";
eval "$RssSource->{$k}{Proceed}";warn if $@;

sub test
{
   my $arg = shift;

   print "fct TEST -> ", $row, "\n";
}

This is working correctly and display:

fct TEST ->

However I would like to be able to pass $str2 as an argument to $RssSource->{$k}{Proceed} but I don't know how, every syntax I tried return an error:

eval "$RssSource->{$k}{Proceed}$str2"
eval "$RssSource->{$k}{Proceed}($str2)"
eval "$RssSource->{$k}{Proceed}"$str2
eval "$RssSource->{$k}{Proceed}"($str2)

May someone tell me how to properly pass an argument to the evaluated function?

Thanks a lot for your help

Regards.

Florent

ehretf
  • 163
  • 10
  • Did you mean `$arg` instead of `$row`, or the other way around? – paddy Oct 03 '12 at 21:31
  • Yes you are right, I have rewritten my code before posting to strictly focus on my issue and didn't change the variable name properly in the test function, sorry – ehretf Oct 04 '12 at 07:57

5 Answers5

5

I'm going to assume that $RssSource->{$k}{Proceed} always contain name or &name, otherwise what you are asking doesn't make much sense.

my $func_name = $RssSource->{$k}{Proceed};
$func_name =~ s/&//;
my $func_ref = \&$func_name;    # Works with strict on!
$func_ref->(@args);

If you want to add some error checking, the following will check if the sub can be called:

defined(&$func_ref)
ikegami
  • 367,544
  • 15
  • 269
  • 518
3

If the string you are evaling always is a sub invocation, you can construct the eval string in one of these ways:

$RssSource->{$k}{Proceed} . '($str2)'

(most general), or

$RssSource->{$k}{Proceed} . "(\"$str2\")"

(inelegant)

Here are the problems your solutions ran into:

eval "$RssSource->{$k}{Proceed}$str2" evaluates to eval "&testABCD". This sub doesn't exist.

eval "$RssSource->{$k}{Proceed}($str2)" evaluates to "&test(ABCD)". Bareword not allowed.

eval "$RssSource->{$k}{Proceed}"$str2 A string has to be followed by some sort of operator, not another variable.

eval "$RssSource->{$k}{Proceed}"($str2) You are trying to call a string as a function. This is not supported in Perl.

amon
  • 57,091
  • 2
  • 89
  • 149
  • Thanks for the analyse and your answer Amon, this is really helpfull to understand what I was doing wrong – ehretf Oct 04 '12 at 08:00
2

If you can change the data in your database to contain just a function name, that is, test rather than &test, you can call a function by a symbolic reference, rather than using eval:

$fn="test";
&{$fn}("argument")
evil otto
  • 10,348
  • 25
  • 38
1

You do not need eval if, as you say, your database just contains function names. You can use them as symbolic references (but please remove the &). The modern way to do it would not be using the & to dereference it but to use the arrow operator:

{
    no strict 'refs'; # hopefully you have strict on already...
    $RssSource->{$k}{Proceed}->($str2);
}
Dondi Michael Stroma
  • 4,668
  • 18
  • 21
  • Thanks Dondi, I have to admit that at first read I prefer Ikegami's answer which is compatible with strict ref. May you tell me why you said this is the modern way to achieve this? – ehretf Oct 04 '12 at 09:15
  • @ehretf ikegami's answer is fine, he does in fact use the arrow operator in the end. I added my own answer because his originally had a mistake in it. Now that it's fixed, I will give it an upvote ;) – Dondi Michael Stroma Oct 04 '12 at 21:21
0

Very similar to ikegami's answer, using the can method, which is more my taste. TIMTOWTDI.

my $func_name = $RssSource->{$k}{Proceed};
$func_name =~ s/&//;
my $func_ref = __PACKAGE__->can($func_name)
  or die "No function named $func_name";
$func_ref->(@args);
Joel Berger
  • 20,180
  • 5
  • 49
  • 104