問題の歴史:
PerlのOOPは、パッケージ(package)とbless関数を通じたリファレンスのバインディングに基づいて実装されています。継承は、Perlがメソッドを検索するパッケージを自動的に決定する@ISA配列によって達成されます。検索メカニズムはMRO(メソッド解決順序)と呼ばれています。
問題:
@ISAの管理が混沌としていて、メソッド検索の順序を理解せずにSUPERを使用すると、エラー、二重呼び出し、または望ましい機能をオーバーライドできないことがよくあります。AUTOLOADの使用は、無限ループを避けるための制御が必要です。
解決策:
コード例:
package Animal; sub speak { print "Animal speaks "; } package Dog; our @ISA = qw(Animal); sub speak { print "Dog barks! "; shift->SUPER::speak(); # 親メソッドの呼び出し } my $dog = bless {}, 'Dog'; $dog->speak;
重要な特徴:
継承チェーンに同じ名前のメソッドを持つ複数の親パッケージがある場合、どれが呼び出されますか?
検索は左から右(@ISAの宣言順)に実行され、最初に見つかったメソッドが呼び出されます。
全ての継承ツリーに特定のメソッドが存在せず、AUTOLOADが親の一つだけに実装されている場合、どうなりますか?
Perlは、メソッド検索チェーンで最初に見つかったクラスのAUTOLOADを呼び出します。他のAUTOLOADは@ISAの前に現れない限りトリガーされません。
メソッドのチェインルックアップ順序を動的に変更できますか?
技術的には、ランタイムで@ISA配列を変更することは可能ですが、脆弱さと追跡が難しいエラーを引き起こす可能性があります。このアプローチは特定のケースでのみ推奨されます。
同じメソッド名を持つ複数の親クラスが使用され、@ISAの順序が手動で予測不可能に変わり、メソッドはSUPERを呼び出し、無限再帰が発生します。
長所:
短所:
@ISAを明示的に宣言することでのみ変更が行われる場合、複数の継承が必要な場合はmro::ConciseやClass::C3などの特化したモジュールを使用します。
長所:
短所: