私は以前にこの質問をしたか、検索して他の人が尋ねるのを見ました-「サブルーチンmySubが../lib/Common.pm line x "で再定義されているという警告が表示されるのはなぜですか?そして、あなたは常に答えを得ます同じコードでサブルーチンを2回宣言しました。このテストパッケージを作成しました。
ファイル全体---------------
package MyCommonPkg;
use strict;
sub thisSubroutineIsNotDefinedAnywhereElse{
}
1;
ファイル全体---------------
そして、私はこのパッケージを使用するPerlスクリプトからこのパッケージを使用します。これは、このパッケージも使用する他のパッケージを使用し、警告が表示されます。
サブルーチンThisSubroutineIsNotDefinedAnywhereElseが../lib/MyCommonPkg.pm行19で再定義されています。
このサブを他の場所で宣言しなかったと約束します。これは循環参照が原因ですか?この警告の原因を追跡して修正するにはどうすればよいですか?
依存ループはありますか? Perlがスクリプトのコンパイルを開始し、次のような行に遭遇した場合:
use PackageA;
Perlはスクリプトのコンパイルを一時停止します。 PackageA.pmを見つけて、コンパイルを開始します。次のような行に遭遇した場合:
use PackageB;
PerlはPackageAのコンパイルを一時停止します。 PackageB.pmを見つけて、コンパイルを開始します。通常、これは正常に完了し、PerlはPackageAのコンパイルの完了に戻り、それが正常に完了するとスクリプトのコンパイルに戻り、それが正常に完了すると、コンパイルされたオペコードの実行を開始します。
ただし、PackageB.pmに次の行が含まれている場合:
use PackageA;
PerlはすでにPackageA.pmを処理しているので何もしないと思うかもしれませんが、問題はまだ完了していないことです。そのため、PerlはPackageBのコンパイルを一時停止し、PackageA.pmのコンパイルを最初から再開します。これにより、PackageAのサブルーチンが再定義されることについて表示されるメッセージがトリガーされる可能性があります。
原則として、2つのパッケージは両方が相互に依存するべきではありません。ただし、3番目のパッケージが原因でループが発生するため、ループの特定が困難な場合があります。
異なるパッケージに同じ名前の2つのサブルーチンがある場合、この警告(警告が有効になっている場合)を「Subroutine new redefined ....」として表示する必要があります。単純な理由(これはGrant McLeanが言ったことに非常に近いですが、まだ正確ではありません)は、パッケージをコンパイルフェーズをスキップして、必要なものにする必要があるためです。このようにして、Perl名前空間マネージャーは、コンパイル時に同じ名前のこのような競合するシンボルを検出せず、モジュールにエラーがなければ、その後も問題なく動作します。
実装することを確認してください
必須モジュール;
ステートメントではなく
モジュールを使用します。
この警告は表示されなくなります。
大文字と小文字を区別しないファイルシステム(Windows、および多くの場合OSX)を使用しているシステムで、use Common
1つのファイルとuse common
別のものでは、このような問題を引き起こす可能性があります。
これは循環依存によって引き起こされる問題のように聞こえます。これを追跡する方法は次のとおりです。問題のクラスが次のようになっている場合:
package AlientPlanet;
use Dinosaurs;
sub has_dinosaurs {...}
1;
次に、例を次のように変更します。
package AlienPlanet;
sub has_dinosaurs {...} # <-- swap
use Dinosaurs; # <-- swap
1;
次のように Carp :: Always を使用してコードをコンパイルします。
⚡ 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
スタックトレースが作成されたので、ループの場所を確認できます。迅速で汚い解決策は、Dinosaurs.pmで Class :: Load を使用することです。
詳細な説明については、私の ブログ投稿 を試してください。
たぶん、これをcgiスクリプトとしてWebサーバーで実行していますか?
この警告を回避するには、ウェブサーバーを再起動する必要があります。
package MyCommonPkg.pm
プログラムを見て、その内容を確認してください。このようなものはありますか?
package MyCommonPkg;
use Exporter qw(import); # Might be "require" and not "use"
our @EXPORT = qw(thisSubroutineIsNotDefinedAnywhereElse);
構文は少し異なる場合があります。表示される主なものは、package
ステートメントであり、Exporter
を使用しており、@EXPORT
配列にサブルーチンの名前が含まれています。
起こっているのは名前空間の衝突です。パッケージは、定義しているのと同じサブルーチンを定義しています。
これを防ぐために、Perlはnamespacesを使用します。デフォルトでは、名前空間はmain
です。ただし、パッケージは、package
コマンドを使用して独自の名前を定義することを想定しています。
サブルーチンまたは変数の完全な名前空間は、名前空間の後に2つのコロンが続き、その後にサブルーチンまたは変数名が続きます。たとえば、 File :: Find を見ると、変数$File::Find::name
および$File::Find::dir
への参照が表示されます。これらは、$name
名前空間の$dir
パッケージ内の変数File/Find.pm
およびFile::Find
です。
物事をより簡単にするために、パッケージはそれらの変数とサブルーチンをmain名前空間にexportできます。たとえば、 File :: Copy を使用すると、Oはこれを実行できます。
...
use File::Copy
...
copy ($file, $to_dir);
の代わりに:
...
use File::Copy
...
File::Copy::copy ($file, $to_dir);
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);
package File::Copy;
は名前空間を定義します。 require Exporter;
と@ISA = qw(Exporter)
を使用すると、パッケージでサブルーチンと変数をmain名前空間にエクスポートできます。 @EXPORT
は、何も通知せずに、copy
およびmove
サブルーチンをmain名前空間にインポートしますそれらが欲しいかどうか!
その最後のビットは非常に重要です。 @EXPORT
を使用するのは悪いマナーと見なされます。代わりに、使用したいサブルーチンをリストする必要がある@EXPORT_OK
を使用する必要があります。 Scalar :: Util のようなより最近のパッケージはこれを行います。
だからいくつかのこと。まず、MyCommonPkg
にpackage MyCommonPkg;
ステートメントがありますか。そうでない場合は、そうする必要があります。これにより、パッケージのサブルーチンと変数がプログラムに悪影響を及ぼすことを防ぎます。次に、@EXPORT
または@EXPORT_OK
を使用できます。
MyCommonPkg
にpackage
ステートメントがある場合、@EXPORT
を使用しますか?その場合、この問題を回避する方法はいくつかあります。
これを行うと、サブルーチンを再定義するときに警告をオフにすることができます。
use MyCommonPkg;
no warnings qw(redefine);
sub thisSubroutineIsNotDefinedAnywhereElse {
...
}
use warnings qw(redefine);
require MyCommonPkg;
の代わりにuse MyCommonPkg;
を使用します。これにより、anyサブルーチンまたは変数が、使用したいものを含むネームスペースにインポートされなくなります。 MyCommonPkg
がthisSubroutineIsNotDefinedAnywhereElse
、foo
、bar
、barfoo
の4つのサブルーチンを定義するとします。これらのサブルーチンのいずれかを使用するため。これを行う必要があります:
my $answer = MyCommonPkg::foo( $input );
楽しくない。
サブルーチンに別の名前を使用してください。このサブルーチンがMyCommonPkg
で定義されていることを文書化しておく必要があります。MyCommonPkg
を使用する場合は、エクスポートされるサブルーチン名を使用しないでください。
最後に、MyCommonPkg
がかなり新しく、何十ものプログラムで使用されていない場合は、@EXPORT_OK
の代わりに@EXPORT
を使用し、MyCommonPkg
を使用するすべてのプログラムを変更して、必要なサブルーチンをエクスポートするようにします。
このような:
use MyCommonPkg qw(foo bar);
この場合、サブルーチンfoo
およびbar
のみがエクスポートされます。サブルーチンthisSubroutineIsNotDefinedAnywhereElse
およびbarfoo
は環境にエクスポートされません。
モジュールの最後にあるこの行を忘れていないことを確認してください:
1;
ここにいくつかの例に含まれていることは知っていますが、見落としやすいので言及しました。私の場合、エラーの唯一の原因であることが判明しました。
私も同じ問題を抱えていました。これは、プログラムがモジュールを使用していて、サブルーチンがプログラムとPerlモジュールの両方に存在していたためです。
パッケージ名として「package Common.pm」を使ってみました。コンパイラがエラーを出しました。非常に親切ですよね?どのバージョンのPerlを使用していますか? 5.10.0と5.12.1で試しました。
コンパイルできる場合でも、.pmファイルを削除することをお勧めします。例えば;
ファイル:some_package.pm;
package some_package;
use strict;
sub yadayadayada { ... }
1;