简体   繁体   English

Perl - 子例程重新定义

[英]Perl - Subroutine redefined

I have asked this question before or searched and seen others ask - why am I getting the warning " Subroutine mySub redefined at ../lib/Common.pm line x "? 我之前已经问过这个问题或者搜查过其他人问过 - 为什么我收到警告“ 子程序mySub重新定义在../lib/Common.pm第x行 ”? and you always get the answer you declared the sub twice in the same code . 并且你总是得到你在同一个代码中声明sub两次的答案。 I created this test package: 我创建了这个测试包:

ENTIRE FILE --------------- 整个文件---------------

package MyCommonPkg;

use strict;

sub thisSubroutineIsNotDefinedAnywhereElse{
}

1;

ENTIRE FILE --------------- 整个文件---------------

and I USE this package from a perl script, which uses other packages, that use this package also, and I get the warning: 我使用perl脚本使用这个包,它使用其他包,也使用这个包,我得到警告:

Subroutine ThisSubroutineIsNotDefinedAnywhereElse redefined at ../lib/MyCommonPkg.pm line 19. 子程序ThisSubroutineIsNotDefinedAnywhereElse在../lib/MyCommonPkg.pm第19行重新定义。

I promise I did not declare this sub anywhere else. 我保证我没有在其他任何地方声明这个子。 So is this caused by a circular reference? 这是由循环引用引起的吗? How can I go about tracking the cause of this warning down and fixing? 如何跟踪此警告的原因并进行修复?

Do you have a dependency loop? 你有依赖循环吗? If Perl starts compiling your script and encounters a line like this: 如果Perl开始编译你的脚本并遇到如下这样的一行:

use PackageA;

Perl pauses the compilation of your script; Perl暂停编写脚本; locates PackageA.pm and starts compiling it. 找到PackageA.pm并开始编译它。 If it encounters a line like this: 如果遇到这样的一行:

use PackageB;

Perl pauses the compilation of PackageA; Perl暂停编译PackageA; locates PackageB.pm and starts compiling it. 找到PackageB.pm并开始编译它。 Normally, that would complete successfully, and Perl would go back to complete compiling PackageA and when that completes successfully it would go back to compiling your script and when that completes successfully it would start to execute the compiled opcodes. 通常情况下,这将成功完成,Perl将返回完成编译PackageA,当成功完成时,它将返回编译脚本,当成功完成时,它将开始执行已编译的操作码。

However , if PackageB.pm contains this line: 但是 ,如果PackageB.pm包含以下行:

use PackageA;

You might expect it would do nothing since Perl has already processed PackageA.pm but the problem is that it hasn't finished yet. 您可能期望它不会做任何事情,因为Perl已经处理了PackageA.pm,但问题是它还没有完成。 So Perl will pause the compilation of PackageB and start compiling PackageA.pm again from the beginning. 所以Perl将暂停PackageB的编译并从头开始再次开始编译PackageA.pm。 That could trigger the message you're seeing about subroutines in PackageA being redefined. 这可能会触发您在重新定义PackageA中的子例程时看到的消息。

As a general rule, two packages should not both depend on each other. 作为一般规则,两个包不应相互依赖。 Sometimes however the loop is harder to locate because it is caused by a third package. 然而,有时循环更难定位,因为它是由第三个包引起的。

When you have two subroutines with the same name in different packages, you ought to see this warning (when warnings are enabled) as "Subroutine new redefined....". 如果在不同的包中有两个具有相同名称的子例程,则应该将此警告(启用警告时)视为“子例程新重新定义的...”。 The simple reason (which is very close to what Grant McLean said, but still not exactly) is you must get your packages skip the compiling phase and make then require. 一个简单的原因(非常接近Grant McLean所说的,但仍然不完全正确)是你必须让你的包跳过编译阶段然后再需要。 This way, the Perl namespace manager will not find any such conflicting symbols with same name at compile time, and if you modules do not have any errors, they will work just fine afterwards also. 这样,Perl命名空间管理器在编译时将找不到任何具有相同名称的冲突符号,如果模块没有任何错误,那么它们之后也会正常工作。

Just make sure you implement 只要确保你实施

require Module; 需要模块;

statement rather than 声明而不是

use Module; 使用模块;

You should not see this warning again. 你不应该再看到这个警告。

如果您使用的是具有不区分大小写的文件系统(Windows,通常是OSX)的系统,并且您在一个文件中use Common并在另一个文件中use common ,则可能会导致此类问题。

This sounds like a problem caused by circular dependencies. 这听起来像是由循环依赖引起的问题。 Here is how to track it down. 以下是如何追踪它。 If your problem class looks like this: 如果你的问题类看起来像这样:

package AlientPlanet;
use Dinosaurs;
sub has_dinosaurs {...}
1;

Then change your example to look like this: 然后将您的示例更改为如下所示:

package AlienPlanet;
sub has_dinosaurs {...}     # <-- swap
use Dinosaurs;              # <-- swap
1;

Now compile your code with Carp::Always like this: 现在使用Carp编译代码::总是这样:

⚡ perl -MCarp::Always -c lib/AlienPlanet.pm                                                                                                            
Subroutine has_dinosaurs redefined at lib/AlienPlanet.pm line 4.
    require AlienPlanet.pm called at lib/Dinosaurs.pm line 4
    Dinosaurs::BEGIN() called at lib/AlienPlanet.pm line 4
    eval {...} called at lib/AlienPlanet.pm line 4
    require Dinosaurs.pm called at lib/AlienPlanet.pm line 5
    AlienPlanet::BEGIN() called at lib/AlienPlanet.pm line 4
    eval {...} called at lib/AlienPlanet.pm line 4
lib/AlienPlanet.pm syntax OK

Now that you have a stacktrace you can see where the loop is. 现在你有了一个堆栈跟踪,你可以看到循环的位置。 The quick and dirty solution is to use Class::Load in Dinosaurs.pm. 快速而肮脏的解决方案是在Dinosaurs.pm中使用Class :: Load

For a more detailed explanation try my blog post . 有关更详细的说明,请参阅我的博文

Are you by any chance running this as a cgi-script on a web-server? 你有没有机会在网络服务器上运行这个cgi脚本?

I find I need to restart the webserver to get around this warning. 我发现我需要重新启动网络服务器以解决此警告。

Take a look at the program package MyCommonPkg.pm and see what it says. 看看package MyCommonPkg.pm程序package MyCommonPkg.pm ,看看它的内容。 Does it have something like this? 它有这样的东西吗?

package MyCommonPkg;

use Exporter qw(import);   #  Might be "require" and not "use"
our @EXPORT = qw(thisSubroutineIsNotDefinedAnywhereElse);

The syntax may be a bit different. 语法可能有点不同。 The main things you should see are the package statement, that it's using Exporter and that the @EXPORT array has your subroutine's name in it. 您应该看到的主要内容是package语句,它使用Exporter并且@EXPORT数组中包含您的子例程的名称。

What is going on is a namespace clash. 发生了什么是命名空间冲突。 Your package is defining the same subroutine you're defining. 您的包正在定义您正在定义的相同子例程。

In order to prevent this from happening, Perl uses namespaces . 为了防止这种情况发生,Perl使用名称空间 By default, your namespace is main . 默认情况下,您的命名空间是main However, packages are suppose to define their own separate namesakes using the package command. 但是,假设package使用package命令定义它们自己的独立名称。

The full namespace of a subroutine or variable is the namespace followed by a double colon, followed by the subroutine or variable name. 子例程或变量的完整命名空间是命名空间,后跟双冒号,后跟子例程或变量名。 For example, of you look at File::Find , you will see references to the variables $File::Find::name and $File::Find::dir . 例如,您查看File :: Find ,您将看到对变量$File::Find::name$File::Find::dir引用。 These are the variables $name and $dir inside the File/Find.pm package under the File::Find namespace. 这些是File::Find命名空间下File/Find.pm包中的变量$name$dir

In order to make things easier for you, packages can export their variables and subroutines into your main namespace. 为了使您更容易,包可以其变量和子例程导出命名空间中。 For example, if I use File::Copy , O can do this: 例如,如果我使用File :: Copy ,O可以这样做:

...
use File::Copy
...
copy ($file, $to_dir);

Instead of: 代替:

...
use File::Copy
...
File::Copy::copy ($file, $to_dir);

If you look at File/Copy.pm , you will see the following: 如果查看File/Copy.pm ,您将看到以下内容:

package File::Copy;
...
our(@ISA, @EXPORT, @EXPORT_OK, $VERSION, $Too_Big, $Syscopy_is_copy);
...
require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(copy move);

The package File::Copy; package File::Copy; defines a namespace. 定义命名空间。 The require Exporter; require Exporter; and the @ISA = qw(Exporter) allows the package to export subroutines and variables into the main namespace. 并且@ISA = qw(Exporter)允许包将子例程和变量导出到命名空间中。 The @EXPORT automatically, without it telling you anything, imports the copy and move subroutines into the main namespace whether you want them or not! @EXPORT自动,无需告诉您任何内容,导入copy并将子例程move命名空间中, 无论您是否需要它们!

That last bit is very important. 最后一点非常重要。 It is now considered bad manners to use @EXPORT . 现在认为使用@EXPORT不礼貌的 Instead, you should use @EXPORT_OK which requires you to list the subroutines you want to use. 相反,您应该使用@EXPORT_OK ,它要求您列出要使用的子例程。 More modern packages like Scalar::Util do this. Scalar :: Util这样的更现代的软件包可以做到这一点。

So several things. 好几件事。 First, does your MyCommonPkg have a package MyCommonPkg; 首先,你的MyCommonPkg是否有一个package MyCommonPkg; statement. 声明。 If not, it should. 如果没有,它应该。 This keeps the packages subroutines and variables from affecting your program in nasty ways. 这使包子程序和变量不会以令人讨厌的方式影响您的程序。 Then, you can use @EXPORT or @EXPORT_OK . 然后,您可以使用@EXPORT@EXPORT_OK

If MyCommonPkg does have a package statement, does it use @EXPORT ? 如果MyCommonPkg确实有一个package语句,它是否使用@EXPORT If so, you have several ways you can avoid this issue: 如果是这样,您有几种方法可以避免此问题:

  • Ignore the warning. 忽略警告。 It's just a warning. 这只是一个警告。 Since you know you're redefining the subroutine, and you want to use your definition of the subroutine, ignore it. 既然您知道要重新定义子例程,并且想要使用子例程的定义,请忽略它。

You can do this to turn off the warning as you redefine the subroutine: 您可以在重新定义子例程时关闭警告:

use MyCommonPkg;

no warnings qw(redefine);
sub thisSubroutineIsNotDefinedAnywhereElse {
   ...
}
use warnings qw(redefine);
  • Use require MyCommonPkg; 使用require MyCommonPkg; instead of use MyCommonPkg; 而不是use MyCommonPkg; . This will prevent the importing of any subroutines or variables into your namespace including ones you wanted to use. 这将阻止将任何子例程或变量导入您的命名空间,包括您想要使用的子例程或变量。 Let's say MyCommonPkg defines four subroutines: thisSubroutineIsNotDefinedAnywhereElse , foo , bar , and barfoo . 假设MyCommonPkg定义了四个子例程: thisSubroutineIsNotDefinedAnywhereElsefoobarbarfoo To use any of these subroutines. 要使用这些子程序中的任何一个。

You need to do this: 你需要这样做:

my $answer = MyCommonPkg::foo( $input );

Not fun. 不好玩。

  • Use another name for your subroutine. 为子例程使用其他名称。 It should have been documented that this subroutine is defined in MyCommonPkg , and if you want to use MyCommonPkg , you shouldn't use subroutine names that are exported. 应记录此子例程在MyCommonPkg定义,如果要使用MyCommonPkg ,则不应使用导出的子例程名称。

  • Finally, if MyCommonPkg is fairly new, and isn't used in dozens of programs, use @EXPORT_OK instead of @EXPORT , and make sure all the programs that use MyCommonPkg are modified to export the subroutines they want: 最后,如果MyCommonPkg是相当新的,并且没有在几十个程序中使用,请使用@EXPORT_OK而不是@EXPORT ,并确保修改所有使用MyCommonPkg的程序以导出他们想要的子程序:

Like this: 像这样:

use MyCommonPkg qw(foo bar);

In this case, only subroutines foo and bar are exported. 在这种情况下,仅导出子例程foobar The subroutines thisSubroutineIsNotDefinedAnywhereElse and barfoo are not exported into your environment. 子例程thisSubroutineIsNotDefinedAnywhereElsebarfoo不会导出到您的环境中。

Make sure you didn't forget this line at the end of your module: 确保您没有忘记模块末尾的这一行:

1;

I know it's been included in a few of the examples here, but I mention it because it is easy to overlook, and in my case it turned out to be the sole cause of the errors! 我知道它已被包含在这里的一些例子中,但我提到它是因为它很容易被忽视,而在我的情况下,它被证明是错误的唯一原因!

I tried to use "package Common.pm" as a package name. 我尝试使用“package Common.pm”作为包名。 The compiler gave me errors. 编译器给了我错误。 Very kind of it eh? 非常好吗? What version of Perl are you using? 您使用的是什么版本的Perl? I tried it on 5.10.0 and 5.12.1. 我在5.10.0和5.12.1上尝试过它。

Even if you can compile it is good practice to remove the .pm file. 即使您可以编译,最好删除.pm文件。 For Example; 例如;

File: some_package.pm; 文件:some_package.pm;

package some_package;
use strict;

sub yadayadayada { ... }

1;

I had the same problem; 我有同样的问题; It was because the program used a module and the subroutine was present both in the program and in the perl module; 这是因为程序使用了一个模块,子程序既存在于程序中,也存在于perl模块中;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM