3

in Perl I know you can use eval and *{$func_name} to call functions dynamically but how do you do this with methods of an object?

for example

EZBakeOven
  sub make_Cake { ... }
  sub make_Donut { ... }
  sub make_CupCake { ... }
  sub make_Soup { ... }

  sub make{
    my($self,$item) = @_;
    if( defined $self->make_$item ){ #call this func if it exists
      $self->make_$item( temp => 300, with_eggs => true ); 
    }
  }

so that if I say something like

$self->make('Cake');
#or maybe I have to use the full method name
$self->make('make_Cake');

it will call

$self->make_Cake();
smonff
  • 3,399
  • 3
  • 36
  • 46
qodeninja
  • 10,946
  • 30
  • 98
  • 152

2 Answers2

4

You should be able to do something like:

sub make {
  my ($self, $item) = @_;
  my $method = "make_$item";
  $self->$method(whatever);
}

Edit: You might want to also use can() to make sure you're calling a method that can be called:

sub make {
  my ($self, $item) = @_;
  my $method = "make_$item";
  if ($self->can($method)) {
    $self->$method(whatever);
  } else {
    die "No such method $method";
  }
}

Edit 2: Actually, now that I think about it, I'm not sure if you really can do that. Code I've written before does something like that, but it doesn't use an object, it uses a class (so you're calling a specific function in a class). It might work as well for objects, but I can't guarantee it.

CanSpice
  • 34,814
  • 10
  • 72
  • 86
  • 1
    awesome! let me give grok that – qodeninja Oct 18 '11 at 22:25
  • Of course then the implicit agreement between the creator of the class and the user thereof, to not tinker with internals of non-api methods is now delegated to the supplier of data. In other words, if you prompt a user "Make what?" CAKE, he says. Fine. "Make what?" MESS he says. Assuming make_MESS exists, it had better be a function intended for the user to manipulate. Because if not, someone aside from the programmer is manipulating an object's internals. In the simple case presented, it seems innocuous. But users can be quite creative ways they find to break things. – DavidO Oct 18 '11 at 22:46
  • The first will work if the method is provided through AUTOLOAD, the second won't. can() also returns a code ref, so you can do: if (my $f = $self->can($method)) { $self->$f(@argumants) } saving an extra method lookup. – runrig Oct 18 '11 at 23:04
  • @runrig, A class that uses `AUTOLOAD` should probably also include a `can()` override that creates the autoloaded function and then calls `$self->SUPER::can()`. It is probably reasonable to consider failure to do so a bug in that class. – Ven'Tatsu Oct 19 '11 at 17:34
2

As by @CanSpice suggested use can to check a methods existence in classes and objects. can returns a reference to the method if it exists, undef otherwise. You can use the returned reference to call the method directly.

The following example calls the method in package/class context. __PACKAGE__ returns the current package/class name.

if ( my $ref = __PACKAGE__->can("$method") ) {
    &$ref(...);
}
fheyer
  • 126
  • 1
  • 4