7

I try to intercept nonexistent methods call in some subclass. Yes, I know about AUTOLOAD, but (for methods) it try to call parent::method first, then UNIVERSAL::method and only then ::AUTOLOAD. But I need call (something like) ::AUTOLOAD at first. Because I want to know what methods subclass try to call from parent.

Give me some advice about it please.

bor
  • 181
  • 1
  • 6
  • [crosspost](http://perlmonks.org/index.pl?node_id=918465) – daxim Aug 04 '11 at 10:43
  • 2
    This is not well formed question, you are missing the "WHY" of what you want to do. You have a problem, you thought up a solution, but that solution does not work halfway through and now you want to just buldoze through it to the end. If you come back to your original problem and state it without letting us guess, it makes it much easier to get a correct answer. – Jiri Klouda Aug 23 '11 at 21:37
  • 1
    Make a stub declaration, like `sub irreal_function;` and that will trigger in its normal place. – tchrist Aug 23 '11 at 22:11

3 Answers3

1
  • If you just want to know what methods are being used, you can use some profiling module like Devel::NYTProf.

  • If you want to react to that during your program execution, you can intercept directly the entersub opcode just as the profiling modules do. See the perlguts or profiling module code for more details.

  • You could probably create a 'Monitor' class with FETCH and EXISTS and tie it to the symbol table hash like: tie %Module::Name:: , Monitor;

But unless we know exactly what you are trying to do and why, it's hard to guess what would be the right solution for you.

Jiri Klouda
  • 1,362
  • 12
  • 25
1

Please heavily consider Jiri Klouda's suggestion that you step back and reconsider what you are trying to accomplish. You almost never want to do what you're trying to do.

But, if you're really sure you want to, here's how to get enough pure Perl rope to hang yourself...

The subs pragma takes a list of sub names to predeclare. As tchrist says above, you can predeclare subs but never actually define them. This will short-circuit method dispatch to superclasses and call your AUTOLOAD immediately.

As for the list of sub names to pass to the pragma, you could use Class::Inspector->methods (thanks to Nic Gibson's answer for teaching me about this module).

According to brian d foy's comment to Nic Gibson's answer, Class::Inspector will not handle methods defined in UNIVERSAL. If you need to do those separately, you can get inspiration from the 'use subs' line in my Class::LazyObject module.

Community
  • 1
  • 1
daxelrod
  • 2,499
  • 1
  • 22
  • 30
0

Why not create an AUTOLOAD sub in the sub-class package which 1) reports the missing method and then 2) dispatches the call to the parent. For this to work you don't defined @ISA in the sub-class.

Something like:

package my_parent;

sub foo { warn "in my_parent::foo" }

package my_subclass;

my $PARENT_CLASS = "my_parent"; # assume only one parent

# Note: no @ISA defined here

sub AUTOLOAD {
  warn "non-existent method $AUTOLOAD called\n";
  my $self = shift;
  (my $method = $AUTOLOAD) =~ s{.*::}{};
  my $super = $PARENT_CLASS . '::' . $method;
  $self->$super(@_);
}

package main;

my $x = bless {}, 'my_subclass';
$x->foo;

The syntax: $self->$super(@_) where $super has double-colons in it tells perl in which package to start looking for the method, e.g.:

$self->my_parent::foo(...)

will look for the foo method starting in the package my_parent regarless of what class $self is blessed into.

ErikR
  • 51,541
  • 9
  • 73
  • 124
  • Thank you for advice. But I tried method like this before. This not help me, because I do not call ->new() directly from subclass, I use code `local *Module::Name::new = sub { Module::Name::Mock->new(); };` and then I do not set @ISA it not working :( – bor Aug 05 '11 at 13:03