在 Perl 中捕获未定义的值访问

Catching undefined value accessing in Perl

如何捕获对成员变量的访问?

$Class1->{Class2}

如果 Class2 字段不存在,是否可以从内部函数中捕获它?

您可以通过提供适当的 getter/setter 方法来环绕您的 class/instance 变量来做到这一点。永远不应该直接访问内部结构,特别是从 class 本身的外部访问(最好不要在 class 内部这样做,除了维护该特定属性的实际方法。这是一个非常基本的示例:

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,因为它从未设置过。

始终使用提供的方法访问 class/object 的属性。像这样的封装是 OO 编程的主要内容。

你可以,但你可能不应该。这里的问题是 - 如果您直接访问 class 中的变量......那么您就可以了。您可以通过一些解决方法来防止这种情况发生 - 这就是像 Moose 这样的东西进来的地方。

还有一些稍微老套的技巧,比如由内而外的对象(我认为这不再是常见的做法 - 几年前 Perl Best Practice 提倡它们)或使用匿名哈希来保存状态。

但失败了 - 为什么不使用访问器,并使用 '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";

这有同样的问题,因为更改方法名称可能会导致事情中断。然而,它的优点是您可以随心所欲地处理 'invalid' 方法调用。

但实际上 - 显式 'get' 和 'set' 方法是大多数用例的更好选择。