如何在perl中的每个类方法之后启动特定的回调子例程?

如何在perl中的每个类方法之后启动特定的回调子例程?,perl,oop,callback,aggregation,Perl,Oop,Callback,Aggregation,让我们假设我已经有了包含多个子例程的Child包和Parent包。这两个包通过聚合组合在一起,就像在perltoot中一样: use warnings; use strict; package Child; sub new { my ($class, %arg) = @_; return bless { %arg }, $class; } sub method_x { warn 'call method x'; } sub method_y { warn

让我们假设我已经有了包含多个子例程的
Child
包和
Parent
包。这两个包通过聚合组合在一起,就像在
perltoot
中一样:

use warnings;
use strict;

package Child;

sub new {
    my ($class, %arg) = @_;
    return bless { %arg }, $class;
}

sub method_x {
    warn 'call method x';
}

sub method_y {
    warn 'call method y';
}

sub method_z {
    warn 'call method z';
}

1;


package Parent;

sub new {
    my ($class, %arg) = @_;
    return bless {
        child => undef,
        %arg,
    }, $class;
}

sub child { shift->{child} }
sub x { shift->child->method_x(@_) }
sub y { shift->child->method_y(@_) }
sub z { shift->child->method_z(@_) }

sub _callback {
    warn "I want to kick this callback after every child methods.";
}

1;


package main;

my $p = Parent->new(
    child => Child->new,
);

$p->x;
$p->y;
$p->z;

1;
过了一会儿,我想为每个
的方法启动
\u回调
,我惊讶于我试图将此回调添加到每个包装器方法(
x
/
y
/
z

我能更优雅地完成这项工作吗?我是否必须在一开始就为一揽子计划提供更大的灵活性?怎么做

欢迎提供任何建议。

一种可能性是使用方法修饰符,该修饰符由对象系统(如Moose或Moo)提供:

输出:

call method_x at - line 7.
called after every Parent (!) invocation at - line 23.
call method_y at - line 8.
called after every Parent (!) invocation at - line 23.
call method_z at - line 9.
called after every Parent (!) invocation at - line 23.
call method_x at - line 7.
called after each method at - line 31.
call method_y at - line 8.
called after each method at - line 31.
call method_z at - line 9.
called after each method at - line 31.
如果确实希望包装
Child
的所有方法,请使用子类:

package WrappedChild {
  use Moose;
  extends 'Child';

  # the /(?=)/ regex matches always
  after qr/(?=)/ => sub {
    warn "called after each method in Child";
  };
}


my $p = Parent->new(child => WrappedChild->new);

$p->x; $p->y; $p->z;
这就产生了

called after each method in Child at - line 32.
called after each method in Child at - line 32.
called after each method in Child at - line 32.
called after each method in Child at - line 32.
called after each method in Child at - line 32.
called after each method in Child at - line 32.
call method_x at - line 7.
called after each method in Child at - line 32.
called after every Parent (!) invocation at - line 22.
call method_y at - line 8.
called after each method in Child at - line 32.
called after every Parent (!) invocation at - line 22.
call method_z at - line 9.
called after each method in Child at - line 32.
called after every Parent (!) invocation at - line 22.
called after each method in Child at - line 32.
called after each method in Child at - line 32.
called after each method in Child at - line 32.
这可能有点过分。坚持使用显式名称可能更好

有关更多信息,请参阅


如果您不想使用任何模块,可以通过丛林符号表进行破解:

for my $name (qw/method_x method_y method_z/) {
  no strict 'refs';
  no warnings 'redefine';
  my $orig = \&{"Child::$name"};
  *{"Child::$name} = sub {
    my @return_values = wantarray ? $orig->() : scalar $orig->();
    warn "called after each method";
    return wantarray ? @return_values : $return_values[0];
  };
}
输出:

call method_x at - line 7.
called after every Parent (!) invocation at - line 23.
call method_y at - line 8.
called after every Parent (!) invocation at - line 23.
call method_z at - line 9.
called after every Parent (!) invocation at - line 23.
call method_x at - line 7.
called after each method at - line 31.
call method_y at - line 8.
called after each method at - line 31.
call method_z at - line 9.
called after each method at - line 31.


请注意,符号表方法会触发所有使用子对象的回调,而不仅仅是通过父对象的回调。有关游戏更改,请参阅问题的最新注释。执行委托方法的更简单方法是使用Moose的
句柄
选项-此处缺少关键信息;你的电话里有什么?它是需要访问父对象的父方法吗?它需要知道正在使用的子对象、调用的方法和/或传递的参数吗?
\u callback
是一个
父对象的方法,它的第一个参数是父对象。我想让孩子保持原样。不用告诉他被利用了。
my $w = wrap(sub { warn "Returning from $_[0]\n" }, Child->new);
$w->x; $w->y; $w->z;