这样做的正确方法就是不要这样做。找一些其他的方式来完成你在做什么。这种技术具有全局变量的所有问题,平方。除非你完全正确地重写了函数,否则你可能会破解你从来不知道存在的各种代码。虽然你可能有礼貌不吹嘘现有的重写,但其他人可能不会。
覆盖system
特别敏感,因为它没有适当的原型。这是因为它做的事情在原型系统中不可表达。这意味着你的覆盖不能做一些system
可以做的事情。即...
system {$program} @args;
这是调用system
的一种有效方式,但你需要阅读exec
文档做到这一点。你可能会认为“哦,我现在不会那么做”,但是如果你使用的任何模块都使用了它,或者它使用了它的任何模块,那么你就没有运气了。
也就是说,与礼貌地重写任何其他函数没有什么不同。你必须捕捉现有的功能,并确保你在新的功能中调用它。无论你在之前还是之后做到这一点,取决于你。
代码中的问题是,检查函数是否被定义的正确方法是defined &function
。采用代码ref,即使是未定义的函数,也会始终返回真实的代码ref。我不知道为什么,也许它像\undef
将返回一个标量ref。为什么调用这个代码引起mysystem()
无限递归是任何人的猜测。
有一个额外的复杂性,你不能参考核心功能。 \&CORE::system
不符合你的意思。你也不能用象征性的参照来解决它。所以,如果你想打电话CORE::system
或取决于定义的现有覆盖,你不能只分配一个或另一个代码ref。你必须分裂你的逻辑。
这是一种方法。
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()更改为仅在真实系统之后运行的挂钩。它获取所有参数和退出代码,它可以更改退出代码,但不会更改实际执行的操作。在钩子之前/之后添加是您可以做的唯一事情,如果您想要兑现现有的覆盖。无论如何,它更安全一些。压倒一切的系统现在是一个子程序,以防止BEGIN变得过于混乱。
您应该可以根据自己的需求进行修改。