這樣做的正確方法就是不要這樣做。找一些其他的方式來完成你在做什麼。這種技術具有全局變量的所有問題,平方。除非你完全正確地重寫了函數,否則你可能會破解你從來不知道存在的各種代碼。雖然你可能有禮貌不吹噓現有的重寫,但其他人可能不會。
覆蓋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變得過於混亂。
您應該可以根據自己的需求進行修改。