Как я могу переопределить функции 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");

9
задан Community 23 May 2017 в 12:25
поделиться

1 ответ

Правильный способ сделать это не делать этого. Найдите какой-то другой способ выполнить то, что вы делаете. Эта техника имеет все проблемы глобальной переменной, в квадрате. Если вы точно правильно не получаете перезапись функции, вы можете сломать все виды кода, которые вы никогда не знали, существовали. И хотя вы можете быть вежливым, не дуя над существующим переопределением, кто-то еще, вероятно, не будет.

Компания Система особенно зависит от того, что у него не имеет правильного прототипа. Это потому, что это делает вещи, не выразимыми в системе прототипы. Это означает, что ваше переопределение не может сделать некоторые вещи, которые могут сделать . А именно ...

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 (), чтобы просто быть крючком, который проходит после реальной системы. Он получает все аргументы и код выхода, и он может изменить код выхода, но он не изменит, что работает () . Добавление до / после того, как крючки - единственное, что вы можете сделать, если вы хотите указать существующее переопределение. Это все равно немного безопаснее. Степень переопределения системы теперь находится в подпрограмме, чтобы продолжать начинаться от слишком загроможденного.

Вы должны быть в состоянии изменить это для ваших нужд.

20
ответ дан 4 December 2019 в 10:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: