Правильный способ сделать это - не делать это.Найдите другой способ выполнить то, что вы делаете.Эта техника имеет все проблемы глобальной переменной в квадрате.Если вы правильно не переписали функцию, вы могли бы сломать все виды кода, о котором вы даже не подозревали.И хотя вы можете быть вежливы, если не откажитесь от существующего переопределения, кто-то другой, вероятно, не будет.
Переопределение 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 (), чтобы он был просто ловушкой, которая запускается после реальной системы.,Он получает все аргументы и код выхода и может изменить код выхода, но не меняет того, что на самом деле делает system()
.Добавление хуков «до / после» - единственное, что вы можете сделать, если хотите использовать существующее переопределение.Все равно немного безопаснее.Беспорядок в системе переопределения теперь находится в подпрограмме, чтобы предотвратить слишком запутанный НАЧАЛО.
Вы должны иметь возможность изменить это для своих нужд.