Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何覆盖Perl函数,启用多个覆盖?_Perl - Fatal编程技术网

如何覆盖Perl函数,启用多个覆盖?

如何覆盖Perl函数,启用多个覆盖?,perl,Perl,前一段时间,我问过关于重写构建perl函数的问题 如何以允许多个覆盖的方式执行此操作?下面的代码生成一个无限递归 这样做的正确方法是什么?如果我重新定义了一个函数,我不想干涉其他人的重新定义 package first; my $orig_system1; sub mysystem { my @args = @_; print("in first mysystem\n"); return &{$orig_system1}(@args); } BEGIN { if (

前一段时间,我问过关于重写构建perl函数的问题

如何以允许多个覆盖的方式执行此操作?下面的代码生成一个无限递归

这样做的正确方法是什么?如果我重新定义了一个函数,我不想干涉其他人的重新定义

package first;

my $orig_system1;
sub mysystem {
  my @args = @_;
  print("in first mysystem\n");
  return &{$orig_system1}(@args);
}

BEGIN {

  if (defined(my $orig = \&CORE::GLOBAL::system)) {
    $orig_system1 = $orig;
    *CORE::GLOBAL::system = \&first::mysystem;
    printf("first defined\n");
  } else {
    printf("no orig for first\n");
  }
}

package main;

system("echo hello world");

正确的方法是不去做。找到其他方法来完成你正在做的事情。这种技术具有全局变量平方的所有问题。除非您完全正确地重写了函数,否则您可能会破坏各种您甚至不知道存在的代码。虽然你可能会礼貌地不去破坏现有的覆盖,但其他人可能不会

重写
系统
特别敏感,因为它没有合适的原型。这是因为它所做的事情在原型系统中无法表达。这意味着您的覆盖无法执行系统可以执行的某些操作。即

system {$program} @args;
这是调用
系统
的有效方法,不过需要阅读
exec
文档才能执行。你可能会想“哦,那么我就不这么做了”,但如果你使用的任何模块都这样做了,或者它使用的任何模块都这样做了,那么你就不走运了

也就是说,礼貌地重写任何其他函数没有什么不同。您必须捕获现有函数,并确保在新函数中调用它。你是在之前还是之后做这件事取决于你自己

代码中的问题是,检查函数是否已定义的正确方法是
defined&function
。获取代码引用,即使是未定义的函数,也会始终返回一个真正的代码引用。我不确定为什么,
\undef
可能会返回一个标量引用。为什么调用此代码引用会导致
mysystem()
无限递归,这是任何人的猜测

还有一个额外的复杂性,就是不能引用核心函数<代码>\&CORE::system并不能满足您的要求。你也不能用象征性的参照来理解它。因此,如果要调用
CORE::system
或现有覆盖(取决于所定义的覆盖),则不能仅将一个或另一个分配给代码引用。必须拆分逻辑

这里有一种方法

package first;

use strict;
use warnings;

sub override_system {
    my $after = shift;

    my $code;
    if( defined &CORE::GLOBAL::system ) {
        my $original = \&CORE::GLOBAL::system;

        $code = sub {
            my $exit = $original->(@_);
            return $after->($exit, @_);
        };
    }
    else {
        $code = sub {
            my $exit = CORE::system(@_);
            return $after->($exit, @_);
        };
    }

    no warnings 'redefine';
    *CORE::GLOBAL::system = $code;
}

sub mysystem {
    my($exit, @args) = @_;
    print("in first mysystem, got $exit and @args\n");
}

BEGIN { override_system(\&mysystem) }

package main;

system("echo hello world");
请注意,我已将mysystem()更改为仅作为跟踪真实系统的钩子。它获取所有参数和退出代码,它可以更改退出代码,但不会更改
system()
实际执行的操作。如果您希望遵守现有的覆盖,那么添加前/后挂钩是唯一可以做的事情。不管怎么说,还是比较安全一点。覆盖系统的混乱现在在一个子例程中,以防止BEGIN变得过于混乱

您应该能够根据自己的需要对其进行修改