Можно ли обмануть Perl, чтобы он использовал переменную %INC и при этом не трогал глобальную %INC?

Я только что нашел сценарий, который мы используем, в котором есть подпрограмма, в которой говорится my %INC, где он хранит некоторые значения поощрений, таким образом, %INC. Это никогда не казалось проблемой, или никто никогда не замечал. Для меня это выдало 20 экранов предупреждений о переопределении, потому что %INC, содержащий все имена файлов, которые Perl имеет done, required или used, был довольно большим, а теперь равен ('stuff' => 123).

Мне действительно нужно пойти и переименовать каждую ссылку на это в подразделе, или есть другой способ заставить Perl простить это...?


Вот часть вывода:

print Dumper \%INC; # I added this line
my %INC;             
print Dumper \%INC; # I added this line
exit;               # I added this line

Выход:

          [...]
          'SqlConnect.pm' => 'lib1/SqlConnect.pm',
          'Lib/RateRequest.pm' => 'Lib/RateRequest.pm'
        };
$VAR1 = {};
[Fri Jun 29 16:09:13 2012] live_batch_test.pl: Subroutine export_fail redefined at /usr/lib/perl5/5.14.2/Carp.pm line 43.
[Fri Jun 29 16:09:13 2012] live_batch_test.pl: Subroutine _cgc redefined at /usr/lib/perl5/5.14.2/Carp.pm line 45.
[Fri Jun 29 16:09:13 2012] live_batch_test.pl: Subroutine longmess redefined at /usr/lib/perl5/5.14.2/Carp.pm line 51.
[Fri Jun 29 16:09:13 2012] live_batch_test.pl: Subroutine shortmess redefined at /usr/lib/perl5/5.14.2/Carp.pm line 71.
[...] (Snipped like 20 screens of redefine warnings)

Предупреждения отображаются только в том случае, если я создаю объект одного из моих классов (который содержит SOAP::WSDL, поэтому в нем много всего). Я не уверен, почему это переопределяют предупреждения. Если %INC пусто, как он может узнать, что что-то переопределяется?


Обновление:

Кажется, вы действительно можете создать лексический my %INC.

use strict; use warnings; use Data::Dumper;
print Dumper \%INC;
{
  my %INC = ('asdf' => 'asdf');
  print Dumper \%INC;
}
print Dumper \%INC;

Производит (отрезано):

          'feature.pm' => 'C:/Perl/lib/feature.pm'
        };
$VAR1 = {
          'asdf' => 'asdf'
        };
$VAR1 = {
          'warnings/register.pm' => 'C:/Perl/lib/warnings/register.pm',

Проблема в моем случае, похоже, не в my %INC, а в %INC = &sub_that_has_my_percent_INC_and_returns_it() в сценарии, который мне действительно нужно require. Теперь у того, в свою очередь, тоже есть use vars qw(%INC). Замена его... ну, я не уверен, что он сломается.


person simbabque    schedule 29.06.2012    source источник
comment
Я собираюсь весело поболтать с парнем, который построил это...   -  person simbabque    schedule 29.06.2012
comment
местный %INC; имело бы больше смысла. Я думаю, вы не можете изменить это сейчас, не вызывая непредвиденных последствий, верно?   -  person d5e5    schedule 29.06.2012
comment
@mkb: нет, я имею в виду %INC.   -  person simbabque    schedule 29.06.2012
comment
И он не используется, чтобы сообщить Perl что-то таким образом, как %INC предназначен для использования. Есть только переменная с таким же именем, потому что парень, который ее создал, не знал, что %INC является зарезервированным именем. В нем просто есть некоторые данные, которые нужны сабвуферу.   -  person simbabque    schedule 29.06.2012
comment
Почему глобальный поиск и замена в файле настолько сложны?   -  person starbolin    schedule 29.06.2012
comment
Да, вы можете создать его. И что? У него ровно нулевое особое значение.   -  person Oleg V. Volkov    schedule 29.06.2012
comment
Спасибо всем за ваш вклад. Я написал, что я сделал, чтобы избавиться от него. Я собираюсь принять ответ @eugeney, так как он наиболее точно ответил на вопрос в теме.   -  person simbabque    schedule 29.06.2012


Ответы (6)


Глобальная переменная %INC (или %main::INC, или %::INC) полностью отличается от переменной %INC с лексической областью действия, созданной с помощью my. Вы можете безопасно использовать my %INC в своей подпрограмме.

person Eugene Yarmash    schedule 29.06.2012
comment
Я так не думаю. Я отредактировал вопрос, чтобы показать, как выглядят предупреждения. - person simbabque; 29.06.2012
comment
Только что проверил это сам, см. отредактированный вопрос. Проблема лежит на уровень выше. Все равно очень странно. - person simbabque; 29.06.2012

Определение my %INC с лексической областью видимости возможно, но эта переменная не имеет абсолютно никакого особого значения. Perl учитывает только глобальные %INC при работе с модульной системой.

Ваша проблема в другом

Просто чтобы развлечь вас примерами, учитывая:

Ааа.pm

package Aaa;
warn "Aaa loaded!";

1;

вкл.pl

use strict;
use warnings;
use Data::Dumper;

use Aaa;
require Aaa;
warn 1, Dumper \%INC;
{
    my %INC;
    use Aaa;
    require Aaa;
    warn 2, Dumper \%INC;
}
warn 3, Dumper \%INC;
my %INC;
use Aaa;
require Aaa;

sub again {
    my %INC;
    require Aaa;
    warn 4, Dumper \%INC;
}

again();
warn 5, Dumper \%INC;

Вы увидите только глобальные %INC в 1 и 3, без каких-либо изменений в лексических, а Aaa.pm все равно будет загружаться ровно один раз.

person Oleg V. Volkov    schedule 29.06.2012
comment
Спасибо за объяснение. Я тоже только что это понял. Проблема в том, что в следующем скрипте есть use vars '%INC' и несколько sub, которые совместно используют %INC, возвращаемый подпрограммой с my %INC. Я пытаюсь избавиться от этого сейчас. - person simbabque; 29.06.2012

perldoc vars говорит, что прагма vars была заменена ключевым словом our.

Следование совету документации, похоже, работает для меня:

package Incentives;

use strict;
use warnings;
use Data::Dump 'dump';

our %INC = ( abc => 123 );

dump \%INC;                   # ( abc => 123 ),
                              # different under use vars '%INC';

use List::Util;               # Loads just fine

package Test;

use Data::Dump 'dump';

dump \%Incentives::INC;       # ( abc => 123 )
dump \%main::INC;             # reference to global %INC

1;
person Zaid    schedule 29.06.2012
comment
Это правильно. Но в моем случае use vars/our %INC было не в package, а в main::. Я изменил ваш код, и теперь он показывает предупреждения. До our %INC он имеет нормальные значения. После него идет abc => 123, а также пара правильных значений, таких как Exporter.pm, List/Util.pm и vars.pm. Я думаю, что с our он просто удалил те, которые определены в main::, и оставил те, которые пришли из Test. Очень странный. - person simbabque; 30.06.2012

У вас будут проблемы, если вы коснетесь глобальной переменной пакета %INC, но вы можете создать все лексические элементы с именем %INC, какие захотите, и это не будет проблемой.

$ perl -e'require CGI; my %INC; require CGI;'

$ perl -e'require CGI; local %INC; require CGI;'
Subroutine export_fail redefined at .../Carp.pm line 64.
Subroutine _cgc redefined at .../Carp.pm line 66.
Subroutine longmess redefined at .../Carp.pm line 72.
Subroutine shortmess redefined at .../Carp.pm line 92.
Subroutine croak redefined at .../Carp.pm line 100.
Subroutine confess redefined at .../Carp.pm line 101.
Subroutine carp redefined at .../Carp.pm line 102.
Subroutine cluck redefined at .../Carp.pm line 103.
Constant subroutine Carp::CALLER_OVERRIDE_CHECK_OK redefined at .../Carp.pm line 108.
Subroutine caller_info redefined at .../Carp.pm line 114.
Subroutine format_arg redefined at .../Carp.pm line 181.
Subroutine get_status redefined at .../Carp.pm line 213.
Subroutine get_subname redefined at .../Carp.pm line 222.
Subroutine long_error_loc redefined at .../Carp.pm line 240.
Subroutine longmess_heavy redefined at .../Carp.pm line 268.
Subroutine ret_backtrace redefined at .../Carp.pm line 276.
Subroutine ret_summary redefined at .../Carp.pm line 309.
Subroutine short_error_loc redefined at .../Carp.pm line 324.
Subroutine shortmess_heavy redefined at .../Carp.pm line 348.
Subroutine str_len_trim redefined at .../Carp.pm line 361.
Subroutine trusts redefined at .../Carp.pm line 376.
Subroutine trusts_directly redefined at .../Carp.pm line 396.
Constant subroutine CGI::XHTML_DTD redefined at .../constant.pm line 151.
Subroutine _ops_to_nums redefined at .../overloading.pm line 10.
Subroutine import redefined at .../overloading.pm line 19.
Subroutine unimport redefined at .../overloading.pm line 37.

То, что ты сказал, не вяжется. Вы должны где-то менять глобальное %INC вместо лексического.

person ikegami    schedule 29.06.2012
comment
Спасибо за простой пример. Вы правы, конечно. Я был (заставлен сделать это). В мой собственный ответ я объясняю более подробно. - person simbabque; 30.06.2012

попробуй с

no warnings 'redefine';

в этой подпрограмме, хотя это может иметь некоторые интересные побочные эффекты в будущем

person Tudor Constantin    schedule 29.06.2012
comment
Спасибо, но я не пытаюсь не показывать предупреждения, я пытаюсь решить большую оплошность. - person simbabque; 29.06.2012

Я думаю, что нашел реальную проблему и способ справиться с ней.

Есть два файла, которые я не создавал.

file1.pl имеет несколько сабвуферов. Один из этих сабвуферов делает что-то вроде этого:

sub foo {
  my %INC = (foo => 'bar'); # lexical variable, does not mess with global %INC
  return %INC;
}

file2.pl выглядит так:

use vars qw(%INC);     # oops! global variable
require 'file1.pl';

sub bar1 {
  if (!$INC{'foo'}) {
    %INC = &foo();     # this is breaking stuff
  }
  my $hashref = {
    'inc' => \%INC,
  }
  return $hashref;
}

sub bar2 {
  if (!$INC{'foo2'}) {
    %INC = &foo();
  }
}
# and so on

В file3.pl, который я создал, у меня есть:

use MyModule;
require 'file2.pl';

my $data = &bar1();
my $obj = MyModule->new();
$obj->doStuff();

Теперь, когда я вызываю doStuff(), он печатает предупреждение о переопределении для каждого элемента в глобальном %INC (который теперь пуст из-за файла2).

Я искал кодовую базу для %INC и обнаружил, что только файл1 и файл2 используют его вообще. Итак, что я сделал, это изменить файл2 на это:

use vars qw();
require 'file1.pl';

my %INC;     # now lexical, but still the same for all subs in this file
sub bar1 {
  if (!$INC{'foo'}) {
    %INC = &foo();     # this is not breaking stuff any more
  }
  my $hashref = {
    'inc' => \%INC,
  }
  return $hashref;
}

sub bar2 {
  if (!$INC{'foo2'}) {
    %INC = &foo();
  }
}
# and so on
person simbabque    schedule 29.06.2012