现代Perl:如何在AUTOLOAD()中实现Redispatching方法?

时间:2011-02-25 10:50:05

标签: perl oop

在OO主题中感到虚弱我尝试使用Modern Perl book进行改进。关于我在以下示例中找到的问题:

package Proxy::Log; 

sub new
{
    my ($class, $proxied) = @_;
    bless \$class, $proxied;
}

sub AUTOLOAD
{
    my ($name) = our $AUTOLOAD =~ /::(\w+)$/;
    Log::method_call( $name, @_ );
    my $self = shift;
    return $$self->$name( @_ );
}

这段代码只是一个划痕或工作示例吗?

我不明白,我怎么能用它,它应该记录在哪里以及它应该记录什么以及我应该如何创建一个对象(什么应该到$proxied)?

我添加了几行来测试它,但没有得到AUTOLOAD功能:

package main;

my $tst = Proxy::Log->new();
say $tst->AnyKindOfSub();

我希望你能带我一些工作代码。我知道我有什么想法,关闭和AUTOLOAD如何工作,但我在这里有点卡住。

2 个答案:

答案 0 :(得分:8)

当注意到bvr时,你已经在构造函数中翻转了你的参数来祝福。因此,尽管这是您的代码的直接问题,但在编写redispatching方法时,一个重要的考虑因素是使用goto &sub语法来擦除AUTOLOAD调用的堆栈帧:

sub AUTOLOAD
{
    my ($name) = our $AUTOLOAD =~ /::(\w+)$/;
    Log::method_call( $name, @_ );
    my $self = shift;
  # return $$self->$name( @_ );   # instead of this, use the following:
    unshift @_, $$self;           # setup argument list
    goto &{ $$self->can($name) }  # jump to method
}

如果redispatched方法使用caller内置任何内容(安装方法,本地化变量,Carp错误报告...),那么这种技术将使caller正常工作。使用原始的return $$self->$name(@_)行始终会报告callerAUTOLOAD子行的最后一行,而后者又可能是难以找到错误的来源。

如果您想稍微改善错误报告,可以将最后一行写为:

 goto &{ $$self->can($name) or Carp::croak "no method '$name' on $$self" };

假设已加载Carp包。

答案 1 :(得分:4)

我认为该示例已在bless的{​​{1}}中切换new个参数。它可能应该是:

Proxy::Log

在下面找到一个功能性示例,因为它可能是预期的。代理类写入日志然后重新调度调用目标对象(bless \$proxied, $class; 类,如下例所示)。

Another