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

Hello
I've got a little problem with method invocation, here is a code:
my $l = new z; $l->{xxx4} = 'wrong way'; my $str = 'xxx'; my $str1 = "4"; my $str2 = "param1"; eval ("print \$l->$str$str1(\$str2)"); package z; sub new { my $class = shift; my $self = {}; return bless $self, $class; }; sub xxx4 { my $self = shift; my $param = shift; return "were requested xxx4: $param \n"; };
It's just an example to show the problem.
The point is:
eval ("print \$l->$str$str1(\$str2)");
I want make same actions without using eval.
At perlobj there is an example:
$method = $fast ? "findfirst" : "findbest"; $fred->$method(@args); # call by name
so for my case it will be something like
my $method = $str.$str1; print $l->$method($str2);
the question is: can it be done at single string?
Thank you.

Replies are listed 'Best First'.
Re: method invocation syntax at perl
by lodin (Hermit) on Jan 03, 2008 at 10:26 UTC

    Yes, it can be done, but I wouldn't recommend it:

    $obj->${\EXPR}(ARGS)
    For instance:
    use strict; sub foo { "@_" } my ($x, $y) = qw/ f oo /; print __PACKAGE__->${\($x . $y)}('FOO'); __END__ main FOO

    lodin

      Thanks a large. This exactly thing i want.
      for my case it will be:
      print $l->${\($str.$str1)}($str2);
      But why don't you recomend this solution?

        For one thing if the two strings are coming from an outside source you've just given them a means to call an arbitrary method in your code; granted it's not a gaping hole, but that's generally enough to raise the hackles of the security conscious.

        That aside, there's also no error checking so if anything does go wrong you merely get the generic "unknown method" error message. Better would be to explicitly validate that it's an allowed method name (either through a dispatch table or hash of valid method names, or at the least through using $obj->can( $method_name ) to check that the method will be callable). If it's not then you can explicitly print your own error message with the two distinct parts of the method name (so you don't have to go diving through the debugger to try and determine if someone tried to call with "xxy4" and "4", or "xxy" and "44", or "xx" and "y44", or . . . ).

        The cake is a lie.
        The cake is a lie.
        The cake is a lie.

Re: method invocation syntax at perl
by jbert (Priest) on Jan 03, 2008 at 11:53 UTC
    It's possible that there is a more readable way to achieve what you want.

    You seem to want to dynamically choose which method to call. Another way to do that is via inheritance. Instead of calculating the method name, instead have the object constructor return an appropriate sub-type, and then call $obj->foo().

    If that doesn't fit your purpose (or the model doesn't fit inheritance well), a good alternative is a dispatch table, where you can stash code in a hashref, and choose which code to call dynamically.

    #!/usr/bin/perl use warnings; use strict; my $str = "foo" . int rand 3; my %dispatch = ( foo0 => sub { print "running foo0\n"; }, foo1 => sub { print "running foo1\n"; }, foo2 => sub { print "running foo2\n"; }, ); my $code = $dispatch{$str}; $code->();
    The code in the dispatch table can, of course, call out to other functions.

    And if the foo1, foo2 etc in your code are sufficiently similar, perhaps you really need a 'foo' function which takes 1, 2 etc as a parameter instead.

      Thank you for your advices, both of them can solve my problem of course. But my question better about perl syntax. :)
Re: method invocation syntax at perl
by ForgotPasswordAgain (Vicar) on Jan 03, 2008 at 10:00 UTC
    I'm not sure what you mean exactly by "done at single string". I guess you mean all in one line. Normally I'd use what you put there, $method = "something"; $obj->$method($str). It is possible to "embed" the string directly in the call, but it requires not using "strict 'refs'". For that, I'll point you to Symbolic references.