2010-11-27 8 views
0

可能性の重複:(!)私は、複数のXML-の解析モジュールはuse Dされているいくつかのレガシーコードで働いている
In Perl, how can I check from which module a given function was imported?どのようにしてPerlメソッドがどのパッケージに属しているのかわかりますか?

これは、同じ名前のメソッドが互いを踏み違えていることを意味します。

特定のメソッドがどのパッケージに属しているかを簡単に知る方法はありますか?

+0

@rafl:関連する質問を見つけるためのThahks。この質問は終了します。 – Zaid

答えて

1

単純な、そしておそらく正しい答えは、与えられた関数をエクスポートした最後にロードされたモジュールは、その関数が使われるモジュールになるということです。

関数(または他のシンボル)をエクスポートすると、受信パッケージのシンボルテーブルが変更されます。したがって、2つのインポート関数がテーブルを変更した場合、最後の変更は保存されているものです。

use Foo;は、です。は、BEGIN { require Foo; Foo->import if Foo->can(import); }に相当します。

importは特別な名前のサブルーチンに過ぎないため、唯一の制限はJ. Random Hackerのねじれた想像力です。 importは、任意のコードとすることができます。それは何でも何もすることができません。たとえば、すでに定義されている関数が上書きされていないことを確認するロジックを含むことができます。

しかし、奇妙なことを除いて、最後にロードされたものは使用中のものになります。


use Foo;BEGIN { require Foo; Foo->import; }に相当する技術的に正しい100%であることが。

このコードは期待通りに機能しません。

正確なコードは私の例とは異なります。

上記のコードは、Perlでのメソッド解決がどのように機能するかに関係しています。

通常、some_subが存在しないFoo->some_subへの呼び出しとAUTOLOAD機能がFooで定義され、some_subAUTOLOAD機能によって処理されるであろう。 AUTOLOAD小切手から免除されるimportの特殊なケースがあります。 perlsub on Autoloadingを参照してください。

AUTOLOADが確認された後(または実際には確認されていない)、私たちは継承をチェックします。一致するファンクションまたはAUTOLOADファンクションの同じチェックが、元のパッケージ@ISAの各アイテムに対して繰り返されます。これは、継承ツリー全体がチェックされるまで、親の親を含む再帰的プロセスです。@ISAは、左から右、深さの最初の順序でチェックされます。今度はAUTOLOAD例外が存在し、importのためにスキップされます。

最終的に、一致するメソッドが見つからない場合は、ユニバーサルベースクラスUNIVERSALに戻ります。関数がUNIVERSALに存在する場合は呼び出され、そうでない場合は関数が見つからないという例外がスローされます。

したがって、Foo->import;コールの場合、UNIVERSAL::importが呼び出されてジョブを処理します。では、この関数は何をしていますか?

のPerl 5.12.2でのコードは次のようになります。機能が最初に行うことは、それがUNIVERSALに呼び出されなかった場合は救済であることを

sub import { 
    return unless $_[0] eq __PACKAGE__; 
    return unless @_ > 1; 
    require warnings; 
    warnings::warnif(
     'deprecated', 
     'UNIVERSAL->import is deprecated and will be removed in a future perl', 
    ); 
    goto &Exporter::import; 
} 

注意。

  • オーバーライドメソッド解決順序を:

    は、今私が言ったすべてはあなたがいくつかのことをしない限り、真です。これを行うと、メソッドの解決は行われますが、それを定義します。私たちがUNIVERSALになるかどうか、いつ空気中に完全に立ち上がり、気まぐれな気分になるかどうか。

  • UNIVERSAL::importを上書きします。 UNIVERSAL :: importをmonkey patchで実行して、必要な処理を行うことができます。再びこれがどのように動作するかは、あなたの気まぐれに完全に従います。

したがって、私が上で示した準相当コードは、何が起こるかをちょうど簡略化したものです。 Perlがどのように動作するかについて多くの詳細を知る必要はないので、わかりやすいと思っていましたが、実際に起こるものと100%は等価ではありません。予期せぬことをすることで同等性が損なわれる。私のコードは、完全に同等のコード

から変化

はまた、私のコードは、一般的にバックUNIVERSAL::canにフォールFoo->can呼び出します。通常のイベントチェーンでは呼ばれていない場所はcanです。これは、Perlでcanの問題を考慮すると、特に毛がかったようになります。

  • canは、継承グラフの任意のクラスによってオーバーライドまたは再実装できます。どのcanが呼び出されるかは、メソッドの解決順序の影響を受けます。多重継承に関するすべての問題がここに当てはまります。
  • canオートロード機能が表示されません。オートローディングはインポートには適用されないため、これは大きな問題ではないようです。問題は、自動ロードを使用する場合、これを考慮するには、canをオーバーロードすることをお勧めします。したがって、これは上記の問題を複合化します。もっとも良いことは、ノンコアモジュールNEXTを使用してメソッドの再ディスパッチを有効にして、チェーン内の各モジュールで処理できることです。残念ながら、これはまれです。

結論

このすべては噛むためにたくさんの一つ地獄です。

私の略記を受け入れることができますが、場合によっては正確ではないこともあります。

または、独自の例外セットを持つ実際のコードを受け入れることができます。

いずれの場合でも、いずれの例の表面を突破しても、対処すべき微妙な問題があります。

+2

Foo – MkV

+0

@MkVにインポートサブがない場合、UNIVERSALのインポート(UNIVERSALで呼び出されない限り何もしません)が呼び出されるというインポートを確認する必要はありません。UNIVERSAL :: importはそれが存在するかどうかをチェックします'UNIVERSAL'で呼び出され、' isa'、 'can'、または' VERSION'を要求通りにエクスポートします。このように 'UNIVERSAL :: import'を使用することは、5.12では非推奨です。それ以外の場合は何もしません。ですから、UNIVERSAL :: importで上記の動作を 'AUTOLOAD'(perlsubを参照)で' import'の特別な例外に追加すると、私が与えたコード例が正しいことになります。 – daotoad

関連する問題