压倒呱呱叫咯咯从Perl的鲤鱼模块中忏悔

Din*_*wda 2 perl overriding carp die

我知道如何覆盖内置的函数perl,我已经覆盖die warn say,因为print并且printf无法覆盖我已将它绑定到我的日志框架的句柄.

覆盖示例warn:

BEGIN{ *CORE::GLOBAL::warn = sub {
                my ($package, $filename, $line, $subroutine) = caller;
                untie *STDERR;
                my $message;
                foreach my $arg (@_) {
                        $message = $message.$arg;
                }
                print STDERR $message;
                tie *STDERR, __PACKAGE__, (*STDERR);
                logmessage("warn",$message,$filename, $line);
                return;
        }
}
Run Code Online (Sandbox Code Playgroud)

现在我可以croak cluck confess carpcarp模块中覆盖Perl吗?

sim*_*que 6

Carp提供的函数只是常规函数,当模块为used 时,它将通过Exporter导入到包中.诀窍是在任何人都可以导入它们之前,尽可能早地Carp命名空间内覆盖它们.然后,当他们这样做时,他们会得到被覆盖的.

在您的脚本中,或在您自己的日志记录模块的最顶层:

BEGIN {
    require Carp;

    # save original croak (will create closure ...)
    my $original_croak = \&Carp::croak;

    no warnings 'redefine';
    *Carp::croak = sub { 
        print "Croaking...\n"
          or $original_croak->("cannot fake croak"); # (... here)
    };
}
Run Code Online (Sandbox Code Playgroud)

您需要加载Carp一次,以便Perl解析代码并在Carp命名空间中安装函数.然后你可以覆盖它们.

稍后,在代码中的其他模块中:

use Carp 'croak';

croak 'foo';
Run Code Online (Sandbox Code Playgroud)

这将产生我们在上面设置的输出.

如果要Carp::croak在新内容中调用原始内容,请将其保存到coderef并保留,如上例所示.

请注意,这仅在替换发生得非常早时才有效.如果你把它放在你自己的日志模块中,并且在Carp加载后它被加载,这将失败.

package Foo;
use Carp;
use Your::Logging::Framework;

croak 'foo';
Run Code Online (Sandbox Code Playgroud)

无法正常工作,因为在您覆盖的位置Carp::croak,Foo::croak已经是原始的副本Carp::croak.

如果你想做那个工作,你总是可以导入自己的carp,croak等等也明确地导入调用者.这将引发一堆警告或抱怨strict,但它应该工作.