Перехватить вызов несуществующих методов в Perl - PullRequest
7 голосов
/ 04 августа 2011

Я пытаюсь перехватить вызов несуществующих методов в некотором подклассе. Да, я знаю об автозагрузке, но (для методов) он сначала пытается вызвать parent :: method, затем UNIVERSAL :: method и только потом :: AUTOLOAD. Но мне нужно сначала позвонить (что-то вроде) :: AUTOLOAD. Потому что я хочу знать, какие методы подкласс пытается вызвать из родительского.

Дайте мне несколько советов по этому поводу, пожалуйста.

Ответы [ 3 ]

1 голос
/ 24 августа 2011
  • Если вы просто хотите узнать, какие методы используются, вы можете использовать какой-либо модуль профилирования, например, Devel :: NYTProf.

  • Если вы хотите отреагировать на это во время выполнения вашей программы, вы можете напрямую перехватить код операции entersub, как это делают модули профилирования. См. Perlguts или код модуля профилирования для более подробной информации.

  • Возможно, вы могли бы создать класс 'Monitor' с помощью FETCH и EXISTS и связать его с хэшем таблицы символов, например: tie% Module :: Name ::, Monitor;

Но если мы точно не знаем, что вы пытаетесь сделать и почему, трудно догадаться, что будет правильным решением для вас.

1 голос
/ 11 сентября 2011

Пожалуйста, внимательно рассмотрите предложение Иржи Клуды, чтобы вы отступили и пересмотрели то, что вы пытаетесь достичь. Вы почти никогда не хотите делать то, что пытаетесь сделать.

Но, если вы действительно уверены, что хотите этого, вот как получить достаточно чистого Perl-каната, чтобы повеситься ...

Прагма subs принимает список подимен для предварительного объявления. Как говорит выше tchrist, вы можете предварительно объявить сабвуферы, но на самом деле никогда не определяете их. Это приведет к короткому замыканию метода, передаваемого суперклассам, и немедленно вызовет ваш AUTOLOAD.

Что касается списка имен, передаваемых в прагму, вы можете использовать Class :: Inspector-> method (благодаря ответу Nic Gibson за то, что вы рассказали мне об этом модуле ).

Согласно комментарию Брайана Д. Фоя к ответу Ника Гибсона, Class :: Inspector не будет обрабатывать методы, определенные в UNIVERSAL. Если вам нужно сделать это отдельно, вы можете получить вдохновение от строки 'use subs' в моем модуле Class :: LazyObject .

0 голосов
/ 05 августа 2011

Почему бы не создать подпрограмму AUTOLOAD в пакете подкласса, которая 1) сообщает об отсутствующем методе, а затем 2) отправляет вызов родителю.Чтобы это работало, вы не определяли @ISA в подклассе.

Что-то вроде:

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;

Синтаксис: $self->$super(@_) где $super содержит двойные двоеточия и указывает perl, в каком пакете начинать поиск метода, например:

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

будет искать метод foo, начинающийся в пакете my_parent независимо от того, какой класс$self благословен.

...