web-dev-qa-db-ja.com

Perl-再定義されたサブルーチン

私は以前にこの質問をしたか、検索して他の人が尋ねるのを見ました-「サブルーチンmySubが../lib/Common.pm line x "で再定義されているという警告が表示されるのはなぜですか?そして、あなたは常に答えを得ます同じコードでサブルーチンを2回宣言しました。このテストパッケージを作成しました。

ファイル全体---------------

package MyCommonPkg;

use strict;

sub thisSubroutineIsNotDefinedAnywhereElse{
}

1;

ファイル全体---------------

そして、私はこのパッケージを使用するPerlスクリプトからこのパッケージを使用します。これは、このパッケージも使用する他のパッケージを使用し、警告が表示されます。

サブルーチンThisSubroutineIsNotDefinedAnywhereElseが../lib/MyCommonPkg.pm行19で再定義されています。

このサブを他の場所で宣言しなかったと約束します。これは循環参照が原因ですか?この警告の原因を追跡して修正するにはどうすればよいですか?

27
user210757

依存ループはありますか? 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番目のパッケージが原因でループが発生するため、ループの特定が困難な場合があります。

34
Grant McLean

異なるパッケージに同じ名前の2つのサブルーチンがある場合、この警告(警告が有効になっている場合)を「Subroutine new redefined ....」として表示する必要があります。単純な理由(これはGrant McLeanが言ったことに非常に近いですが、まだ正確ではありません)は、パッケージをコンパイルフェーズをスキップして、必要なものにする必要があるためです。このようにして、Perl名前空間マネージャーは、コンパイル時に同じ名前のこのような競合するシンボルを検出せず、モジュールにエラーがなければ、その後も問題なく動作します。

実装することを確認してください

必須モジュール;

ステートメントではなく

モジュールを使用します。

この警告は表示されなくなります。

24
user1587276

大文字と小文字を区別しないファイルシステム(Windows、および多くの場合OSX)を使用しているシステムで、use Common 1つのファイルとuse common別のものでは、このような問題を引き起こす可能性があります。

7
hobbs

これは循環依存によって引き起こされる問題のように聞こえます。これを追跡する方法は次のとおりです。問題のクラスが次のようになっている場合:

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 を使用することです。

詳細な説明については、私の ブログ投稿 を試してください。

4
Eric Johnson

たぶん、これをcgiスクリプトとしてWebサーバーで実行していますか?

この警告を回避するには、ウェブサーバーを再起動する必要があります。

2
Phluks

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 のようなより最近のパッケージはこれを行います。

だからいくつかのこと。まず、MyCommonPkgpackage MyCommonPkg;ステートメントがありますか。そうでない場合は、そうする必要があります。これにより、パッケージのサブルーチンと変数がプログラムに悪影響を及ぼすことを防ぎます。次に、@EXPORTまたは@EXPORT_OKを使用できます。

MyCommonPkgpackageステートメントがある場合、@EXPORTを使用しますか?その場合、この問題を回避する方法はいくつかあります。

  • 警告を無視します。これは単なる警告です。サブルーチンを再定義していることを知っていて、サブルーチンの定義を使用したい場合は、無視してください。

これを行うと、サブルーチンを再定義するときに警告をオフにすることができます。

use MyCommonPkg;

no warnings qw(redefine);
sub thisSubroutineIsNotDefinedAnywhereElse {
   ...
}
use warnings qw(redefine);
  • require MyCommonPkg;の代わりにuse MyCommonPkg;を使用します。これにより、anyサブルーチンまたは変数が、使用したいものを含むネームスペースにインポートされなくなります。 MyCommonPkgthisSubroutineIsNotDefinedAnywhereElsefoobarbarfooの4つのサブルーチンを定義するとします。これらのサブルーチンのいずれかを使用するため。

これを行う必要があります:

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

楽しくない。

  • サブルーチンに別の名前を使用してください。このサブルーチンがMyCommonPkgで定義されていることを文書化しておく必要があります。MyCommonPkgを使用する場合は、エクスポートされるサブルーチン名を使用しないでください。

  • 最後に、MyCommonPkgがかなり新しく、何十ものプログラムで使用されていない場合は、@EXPORT_OKの代わりに@EXPORTを使用し、MyCommonPkgを使用するすべてのプログラムを変更して、必要なサブルーチンをエクスポートするようにします。

このような:

use MyCommonPkg qw(foo bar);

この場合、サブルーチンfooおよびbarのみがエクスポートされます。サブルーチンthisSubroutineIsNotDefinedAnywhereElseおよびbarfooは環境にエクスポートされません。

1
David W.

モジュールの最後にあるこの行を忘れていないことを確認してください:

1;

ここにいくつかの例に含まれていることは知っていますが、見落としやすいので言及しました。私の場合、エラーの唯一の原因であることが判明しました。

0
todd412

私も同じ問題を抱えていました。これは、プログラムがモジュールを使用していて、サブルーチンがプログラムとPerlモジュールの両方に存在していたためです。

0
Megiddo

パッケージ名として「package Common.pm」を使ってみました。コンパイラがエラーを出しました。非常に親切ですよね?どのバージョンのPerlを使用していますか? 5.10.0と5.12.1で試しました。

コンパイルできる場合でも、.pmファイルを削除することをお勧めします。例えば;

ファイル:some_package.pm;

package some_package;
use strict;

sub yadayadayada { ... }

1;
0
J.J.