【问题标题】:Intercept nonexistent methods call in Perl在 Perl 中拦截不存在的方法调用
【发布时间】:2011-08-04 08:32:57
【问题描述】:

我尝试拦截某些子类中不存在的方法调用。 是的,我知道 AUTOLOAD, 但是(对于方法)它首先尝试调用 parent::method,然后是 UNIVERSAL::method,然后才调用 ::AUTOLOAD。 但我首先需要调用(类似于)::AUTOLOAD。 因为我想知道子类尝试从父类调用哪些方法。

请给我一些建议。

【问题讨论】:

  • 这不是很好的问题,你错过了你想做的“为什么”。你有一个问题,你想出了一个解决方案,但这个解决方案在中途不起作用,现在你只想把它推到最后。如果你回到原来的问题并在不让我们猜测的情况下陈述它,它会更容易得到正确的答案。
  • 做一个存根声明,比如sub irreal_function;,它将在其正常位置触发。

标签: perl autoload


【解决方案1】:
  • 如果您只想知道正在使用哪些方法,可以使用一些分析模块,例如 Devel::NYTProf。

  • 如果您想在程序执行期间对此做出反应,您可以像分析模块一样直接拦截 entersub 操作码。有关详细信息,请参阅 perlguts 或分析模块代码。

  • 您可能可以使用 FETCH 和 EXISTS 创建一个“监视器”类,并将其与符号表哈希绑定,例如:tie %Module::Name:: , Monitor;

但除非我们确切地知道您想要做什么以及为什么,否则很难猜出适合您的解决方案。

【讨论】:

    【解决方案2】:

    请认真考虑 Jiri Klouda 的建议,即您退后一步,重新考虑您要完成的工作。你几乎从不想做你想做的事。

    但是,如果您真的确定要这样做,这里是如何获得足够的纯 Perl 绳索来吊死自己...

    subs pragma 需要一个子名称列表来预先声明。正如 tchrist 上面所说,您可以预先声明 subs,但从不实际定义它们。这会将方法分派到超类并立即调用您的 AUTOLOAD。

    至于要传递给 pragma 的子名称列表,您可以使用 Class::Inspector->methods(感谢 Nic Gibson's answer 教我有关此模块的知识)。

    根据 brian d foy 对 Nic Gibson 的回答的评论,Class::Inspector 不会处理 UNIVERSAL 中定义的方法。如果您需要单独执行这些操作,可以从我的 Class::LazyObject 模块中的“使用 subs”行中获得灵感。

    【讨论】:

      【解决方案3】:

      为什么不在子类包中创建一个AUTOLOAD sub,它 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(...)
      

      将在 my_parent 包中查找 foo 方法,无论 $self 属于哪个类。

      【讨论】:

      • 感谢您的建议。但我以前试过这样的方法。这对我没有帮助,因为我不直接从子类调用 ->new(),我使用代码 local *Module::Name::new = sub { Module::Name::Mock->new(); }; 然后我没有设置 @ISA 它不起作用:(
      猜你喜欢
      • 2012-06-08
      • 2021-09-16
      • 2011-02-11
      • 2014-10-11
      • 2012-11-04
      • 2015-04-29
      相关资源
      最近更新 更多