是否有可能欺骗Perl使用变量%INC仍然保持全局%INC不受影响?

时间:2012-06-29 14:21:50

标签: perl global-variables require perlvar

我刚刚找到了一个我们正在使用的脚本,其中有一个子my %INC,其中存储了一些关于激励的值,因此%INC。这似乎永远不会成为一个问题,或者没有人注意到。对我来说,它产生了20个重新定义的重新警告屏幕,因为%INC包含所有文件名Perl do ne,require d或use d,非常大,并且现在是('stuff' => 123)

我是否真的必须在sub中重命名每一个引用,或者是否有另一种方法让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)。取而代之......好吧,我不确定那会破坏什么。

6 个答案:

答案 0 :(得分:4)

全局变量%INC(或%main::INC%::INC)是与使用%INC创建的词法范围my完全不同的变量。您可以在子例程中安全地使用my %INC

答案 1 :(得分:2)

定义lexicaly scoped my %INC是可能的,但这个变量绝对没有特殊含义。在使用模块系统时,Perl仅考虑全局%INC

您的问题在其他地方

只是为了给你带来一些例子,给出:

Aaa.pm

package Aaa;
warn "Aaa loaded!";

1;

inc.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;

您只会在1和3中看到全局%INC,而不会对词法变化进行任何更改,Aaa.pm仍然只会加载一次。

答案 2 :(得分:1)

perldoc vars表示vars pragma已被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;

答案 3 :(得分:1)

如果触摸全局包变量%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.

你说的不是jive。您必须在某处更改全局%INC而不是词法。

答案 4 :(得分:0)

尝试

no warnings 'redefine';

在那个子程序中,虽然这可能会在将来产生一些有趣的副作用

答案 5 :(得分:0)

我认为我发现了实际问题以及解决问题的方法。

我没有创建两个文件。

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中的每个项目打印一个重新定义的警告(由于file2,该项目现在为空)。

我在代码库中搜索了%INC,发现只有file1和file2才使用它。所以我所做的就是将file2更改为:

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