重新定义Perl子例程

重新定义Perl子例程,perl,subroutine,Perl,Subroutine,我以前问过这个问题,或者搜索过,看到其他人问过——为什么我收到警告“Subroutine mySub在../lib/Common.pm第x行重新定义”?你总是会得到答案,你在同一个代码中声明了sub两次。我创建了这个测试包: 整个文件--------------- 整个文件--------------- 我使用perl脚本中的这个包,它使用其他包,也使用这个包,我得到警告: 子例程此子例程未定义在../lib/MyCommonPkg.pm第19行的任何地方重新定义 我保证我没有在其他地方申报这艘

我以前问过这个问题,或者搜索过,看到其他人问过——为什么我收到警告“Subroutine mySub在../lib/Common.pm第x行重新定义”?你总是会得到答案,你在同一个代码中声明了sub两次。我创建了这个测试包:

整个文件---------------

整个文件---------------

我使用perl脚本中的这个包,它使用其他包,也使用这个包,我得到警告:

子例程此子例程未定义在../lib/MyCommonPkg.pm第19行的任何地方重新定义


我保证我没有在其他地方申报这艘潜艇。那么这是由循环引用引起的吗?我如何才能跟踪此警告的原因并进行修复?

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

我尝试使用“package Common.pm”作为包名。编译器给了我错误。非常好,嗯?您使用的是什么版本的Perl?我在5.10.0和5.12.1上试过

即使可以编译,删除.pm文件也是一种很好的做法。比如,

文件:some_package.pm

package some_package;
use strict;

sub yadayadayada { ... }

1;

你有依赖循环吗?如果Perl开始编译您的脚本并遇到这样一行代码:

use PackageA;
use PackageB;
package AlientPlanet;
use Dinosaurs;
sub has_dinosaurs {...}
1;
package AlienPlanet;
sub has_dinosaurs {...}     # <-- swap
use Dinosaurs;              # <-- swap
1;
⚡ 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
Perl暂停脚本的编译;找到PackageA.pm并开始编译它。如果遇到这样一条线:

use PackageA;
use PackageB;
package AlientPlanet;
use Dinosaurs;
sub has_dinosaurs {...}
1;
package AlienPlanet;
sub has_dinosaurs {...}     # <-- swap
use Dinosaurs;              # <-- swap
1;
⚡ 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
Perl暂停PackageA的编译;找到PackageB.pm并开始编译它。通常,这将成功完成,Perl将返回到完成编译PackageA,当成功完成时,它将返回到编译脚本,当成功完成时,它将开始执行编译后的操作码

但是,如果PackageB.pm包含此行:

use PackageA;
由于Perl已经处理了PackageA.pm,您可能会认为它不会做任何事情,但问题是它还没有完成。因此,Perl将暂停PackageB的编译,并从头开始再次编译PackageA.pm。这可能会触发您看到的有关重新定义PackageA中的子例程的消息


作为一般规则,两个包不应该都相互依赖。但是,有时由于循环是由第三个包引起的,所以很难找到循环。

您是否有可能在web服务器上以cgi脚本的形式运行此循环


我发现需要重新启动Web服务器以避开此警告。

请确保您没有忘记模块末尾的这一行:

1


我知道这里的一些例子中包含了它,但我提到它是因为它很容易被忽略,在我的例子中,它是导致错误的唯一原因

当您在不同的包中有两个同名的子例程时,您应该将此警告(当启用警告时)视为“Subroutine new redefined…”。 简单的原因(与Grant McLean所说的非常接近,但仍然不完全相同)是您必须让您的包跳过编译阶段,然后进行必要的修改。这样,Perl命名空间管理器在编译时就不会发现任何同名的冲突符号,如果您的模块没有任何错误,那么它们在编译后也可以正常工作

只要确保你能实现

需要模块

语句而不是

使用模块


您不应该再次看到此警告。

这听起来像是由循环依赖关系引起的问题。下面是如何找到它的。如果您的问题类如下所示:

use PackageA;
use PackageB;
package AlientPlanet;
use Dinosaurs;
sub has_dinosaurs {...}
1;
package AlienPlanet;
sub has_dinosaurs {...}     # <-- swap
use Dinosaurs;              # <-- swap
1;
⚡ 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
然后将示例更改为如下所示:

use PackageA;
use PackageB;
package AlientPlanet;
use Dinosaurs;
sub has_dinosaurs {...}
1;
package AlienPlanet;
sub has_dinosaurs {...}     # <-- swap
use Dinosaurs;              # <-- swap
1;
⚡ 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
现在有了stacktrace,您可以看到循环的位置了。快速而肮脏的解决方案是在恐龙网站中使用


有关更详细的说明,请尝试my.

查看程序包MyCommonPkg.pm
并查看它的说明。它有这样的东西吗

package MyCommonPkg;

use Exporter qw(import);   #  Might be "require" and not "use"
our @EXPORT = qw(thisSubroutineIsNotDefinedAnywhereElse);
语法可能有点不同。您应该看到的主要内容是
语句,它正在使用
导出程序
,并且
@EXPORT
数组中包含您的子例程名称

正在发生的是名称空间冲突。您的包定义的子例程与您定义的子例程相同

为了防止这种情况发生,Perl使用名称空间。默认情况下,名称空间是
main
。但是,假定包使用
package
命令定义自己的单独名称

子例程或变量的完整命名空间是命名空间,后跟双冒号,后跟子例程或变量名。例如,当您查看时,您将看到对变量
$File::Find::name
$File::Find::dir
的引用。这些是
File::Find
命名空间下
文件/Find.pm
包中的变量
$name
$dir

为了使事情更简单,包可以将其变量和子例程导出到主命名空间中。例如,如果我使用,O可以这样做:

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

...
use File::Copy
...
File::Copy::copy ($file, $to_dir);
如果查看
文件/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);
包文件::复制定义名称空间。
要求出口商
@ISA=qw(Exporter)
允许包将子例程和变量导出到主命名空间中。
@EXPORT
会自动将
复制
移动
子例程导入主命名空间,而无需告诉您任何信息

最后一点非常重要。现在使用
@EXPORT
被认为是不礼貌的。相反,您应该使用
@EXPORT\u OK
,这要求您列出要使用的子例程。像这样更现代的软件包可以做到这一点

所以