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