2017-06-21 6 views
0

メンバー変数へのアクセスを取得するにはどうすればよいですか?Perlでアクセスする未定義の値をキャッチ

$Class1->{Class2} 

Class2フィールドが存在しない場合は、ですが内部関数からこれをキャッチすることは可能でしょうか?

+2

内部には移動しないでください。代わりにアクセサメソッドを定義してください。オブジェクトの内部実装が変更される可能性があります。代わりに定義されたAPIを使用してください。また、これはクラスではなくオブジェクトです。 – simbabque

+2

キーが追加されるのを防ぐことができますが、存在しないキーからの読み取りを妨げません。あなたが暗示していたように、これは 'undef'を返します。これは値を期待している場合にエラーを引き起こすはずです。 – ikegami

+3

ハッシュベースの代わりにオブジェクトを配列ベースにすると、間違って(少なくとも意図せずに)使用しにくくすることができます。他のトリックもありますが、ある時点では、「あなたが提供したアクセサーを使用しないと、あなたが噛まれるとあなた自身の責任です! – ikegami

答えて

0

これは、クラス/インスタンス変数を囲む適切なゲッター/セッターメソッドを提供することによって行います。内部には、それが特定の属性を維持し、実際の方法を除いて、いずれかのクラスの中で、そうしないことが賢明です(特にクラス自体の外側から、直接アクセスすべきではありませんここでは非常に基本的な例を示します。

use warnings; 
use strict; 

package A; 

sub new { 
    my ($class, %args) = @_; 
    my $self = bless {}, $class; 

    $self->x($args{x}); 
    $self->y($args{y}); 

    return $self; 
} 
sub x { 
    my ($self, $x) = @_; 
    $self->{x} = $x if defined $x; 
    return $self->{x} // 1; 
} 
sub y { 
    my ($self, $y) = @_; 
    $self->{y} = $y if defined $y; 
    return $self->{y} // 2; 
} 

package main; 

my $obj = A->new(x => 5, y => 3); 

print $obj->x ."\n"; 
print $obj->y ."\n"; 

print $obj->{x}と同じように簡単にできますが、問題がどこにあるのでしょうか。コードがこれよりもはるかに複雑で何らかの理由で属性名をfooに変更しますが、x()メソッド?$obj->{x}は今度はundefとなりません。

クラス/オブジェクトの属性にアクセスするために、常に提供されているメソッドを使用してください。このようなカプセル化はオブジェクト指向プログラミングの重要な要素です。

+2

DRY - 書き込みアクセッサに浪費される行の量で支払いを受けていない場合を除きます。 –

+1

原則は問題ありませんが、呼び出し元が値をundefに設定しようとすると(意図的に、またはそうではなく)、これらのアクセサが非常にうまく機能しなくなります。与えられた引数の数を調べるべきです( 'my $ self = shift; $ self - > {x} = @_; $ self - > {x};'を返す)希望。 – ikegami

1

あなたはそうかもしれませんが、おそらくそうではありません。ここで問題となるのは、クラス内の変数に直接アクセスすれば、できることです。これはいくつかの回避策でこれを防ぐことができます - これはMooseのようなものが入ってくる場所です。

そして、内側にあるオブジェクトのようなややハックトリックがいくつかあります。ベストプラクティスは数年前にそれらを提唱した)、または状態を保持するために匿名のハッシュを使用する。

しかし、それは失敗します。アクセサーを使用して、AUTOLOADを使用して自動生成するのはなぜでしょうか。

#!/usr/bin/env perl 

package MyClass; 
use strict; 
use warnings; 

use vars '$AUTOLOAD'; 
sub AUTOLOAD { 
    my ($self) = @_; 

    my $subname = $AUTOLOAD =~ s/.*:://r; 

    if ($self -> {$subname}) { 
     return $self -> {$subname}; 
    } 
    warn "Sub called $subname was called\n"; 
    return "$subname"; 
} 

sub new { 
    my ($class) = @_; 
    my $self = {}; 
    bless $self, $class; 
} 

package main; 
use strict; 
use warnings; 

my $object = MyClass -> new; 
$object -> {var} = "fleeg"; 

print "Undef fiddle was: ", $object -> fiddle,"\n"; 
print "But 'var' was: ", $object -> var,"\n"; 

これは、同じ問題を抱えている、その変更メソッド名で物事が破損する可能性があります。ただし、好きなように「無効な」メソッド呼び出しを処理できるという利点があります。

しかし、実際に明示的な 'get'と 'set'メソッドは、ほとんどのユースケースにとってより良い選択です。

+1

'AUTOLOAD'は私がこれをお勧めする最後のものです。明確に定義されたリスト用のアクセサを生成するには、コードは必要なく、はるかに堅牢です。それ以外に、 'Object :: Accessor'、' Class :: Accessor :: * '、' Moo(se)? 'などがあります。 –

+1

内側のオブジェクトの良いプライマーはhttp://perltraining.comです。au/tips/2006-03-31.htmlこれまで以上に多くのモジュールがありましたが、私はそれが本当にうまくコンセプトを説明すると思います。 –

関連する問題