2017-06-21 60 views
0

如何捕獲對成員變量的訪問?在Perl中捕獲未定義的值訪問

$Class1->{Class2} 

如果Class2字段不存在,是否有可能從內部函數中捕獲?

+2

你不應該去內部。改爲定義訪問器方法。你的對象的內部實現可以改變。改爲使用定義的API。另外,這是一個對象,而不是一個類。 – simbabque

+2

您可以防止添加密鑰,但這並不妨礙從不存在的密鑰讀取。正如你暗示的那樣,這會返回'undef',如果你期待一個值,這應該會導致錯誤。 – ikegami

+3

你可以使你的對象基於數組,而不是基於散列,以使它更難使用不正確(至少是無意)。還有其他一些技巧,但在某些時候,你只是說:「如果你不使用我們提供的訪問器,如果你被咬了,這是你自己的錯誤!」 – ikegami

回答

0

您可以通過提供適當的getter/setter方法來包裝類/實例變量。在內部不應該直接訪問,特別是從類本身以外(這是明智的類內沒有這樣做要麼,除了爲維護特定屬性的實際方法,這裏是一個非常簡單的例子:

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},但這就是您的問題所在。當代碼比這複雜得多時,出於某種原因,您想將x屬性名稱更改爲foo,但保留x()方法$obj->{x}現在是undef,因爲它從未設置過。始終使用提供的方法來訪問類/對象的屬性。諸如此類的封裝是面向對象編程的主要部分。

+2

DRY - 除非您通過寫入訪問者浪費的行數獲得付款。 –

+1

原理很好,但是當調用者嘗試將值設置爲undef(有意或無意)時,那些訪問器失敗的情況非常糟糕。你應該檢查提供的參數個數('my $ self = shift; $ self - > {x} = shift if @_; return $ self - > {x};')並且* add *檢查和轉換if期望。 – ikegami

1

你可以,但你可能不應該。這裏的問題是 - 如果你直接訪問類中的變量,那麼你就可以。你可以通過一些解決方法來避免這種情況 - 這就是Moose進來的地方。

而且還有一些有點冒險的技巧,像內向外對象(我認爲這些技巧不再常見 - Perl最佳實踐在幾年前提倡他們)或使用匿名哈希來維持狀態。

但是失敗 - 爲什麼不使用存取器,並使用'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)?, etc. –

+1

http://perltraining.com是一個很好的內外物體入門書。au/tips/2006-03-31.html雖然現在有很多模塊可以做到這一點,但我認爲它很好地解釋了這個概念。 –

相關問題