質問の背景:
Perl 5の最初のリリースから、言語はパッケージへのリンクのバインディング(祝福)を介して基本的なオブジェクトモデルをサポートしています。Perlでは、オブジェクトは通常のリンク(ハッシュ、配列、またはスカラーへのリンク)であり、bless関数によって「祝福」されており、システムがパッケージ(名前空間)を介してメソッドを見つけることを可能にします。
問題:
祝福されていないリンクは単なるデータ構造のままであり、それに対してメソッドを呼び出そうとするとランタイムエラーが発生します。プログラマはリンクのタイプに不注意だと、オブジェクトの内部を誤って操作し、カプセル化を破る危険があります。また、制御なしで「生」のデリファレンス操作{}や@{}を使用すると、追跡が難しいバグにつながります。
解決策:
オブジェクトは常にblessを介して正しく作成し、その後はデリファレンスを介してのみオブジェクトのデータにアクセスし、Scalar::Utilモジュールを使用してタイプを確認します(ref、blessed)。クラスのメソッドの外で構造体への直接アクセス(例えば、$obj->{key})を避け、データへのアクセスを制御するためにアクセサ(ゲッター/セッター)を実装することが常に推奨されます。
コード例:
package Animal; sub new { my $class = shift; my $self = { name => shift }; bless $self, $class; return $self; } sub name { my $self = shift; $self->{name} = shift if @_; return $self->{name}; } my $dog = Animal->new("Rex"); print $dog->name; # アクセサを介した安全なアクセス print $dog->{name}; # 直接アクセスは推奨されません
重要な特徴:
blessedやrefを通じて行うことで、バグの数が大幅に減少します祝福なしでハッシュへの通常のリンクをオブジェクトとして使用できますか?
いいえ、blessを呼び出さなければ、リンクはパッケージとの関連がなく、Perlはメソッドを見つけられません("Can't call method"というエラーが発生します)。内部構造は同じでもです。
変数がオブジェクトであることを安全に確認するにはどうすればよいですか?
Scalar::Util::blessed($obj)関数を使用して、リンクが祝福されているかどうかを確認します。祝福されたリンクだけがオブジェクトと見なされます。
use Scalar::Util 'blessed'; my $obj = {}; print blessed($obj) ? 'yes' : 'no'; # 'no'と表示されます
非オブジェクトリンクでエラーなしにメソッドを呼び出すことはできますか?
非祝福リンクでメソッドを呼び出すと致命的なエラーが発生します:Perlはリンクが自分のパッケージについて知っていることを期待します。例外としてAUTOLOADメカニズムと動的なロードがありますが、これはエラーを引き起こすアンチパターンです。
若手開発者が手動で構造体$person = {name => 'Vasya'}を作成し、祝福を呼び出すことを忘れたため、$person->name()を呼び出そうとすると、ランタイムエラーが発生します。
長所:
短所:
コードでは常にオブジェクトを作成する際にblessが呼び出され、データへのアクセスには常にname()メソッドが使用されます。blessed()を介してのチェックにより、メソッドの実行前にエラーを処理できます。
長所:
短所: