There's a nifty module on CPAN which ensures that object attributes can only be retrieved and altered inside the objects' class: Alter by Anno. Sample:
package Foo;
use Alter ego => {};
my @attr = qw ( bar quux );
sub new {
my $class = shift;
my $obj = {};
bless $obj, $class;
if ( @_) {
@_ % 2 and die "odd number of arguments, aborted";
my %args = @_;
my %params;
for (@attr) {
$params{ $_} = delete $args{ $_};
}
warn "unknown key $_!\n" for keys %args;
for ( keys %params) {
$obj->$_( $params{ $_});
}
}
return $obj;
}
sub bar {
my $obj = shift;
ego( $obj)->{ bar} = shift if @_;
return ego( $obj)->{ bar};
}
sub quux {
my $obj = shift;
ego( $obj)->{ quux} = shift if @_;
ego( $obj)->{ quux};
}
package main;
print "\nOutput:\n"
my $foo = Foo->new( foo => 1, bar => 2, quux => 3);
print "\$foo reference is '$foo'\n";
$foo->{bar} = "something"; # hash lookup
$foo->bar(5); # method
print "method: \$foo->bar( ) = ", $foo->bar( ), "\n";
print "hash: \$foo->{ bar} = ", $foo->{ bar}, "\n";
__END__
Output:
unknown key foo!
$foo reference is 'Foo=HASH(0x8a007a4)'
method: $foo->bar( ) = 5
hash: $foo->{ bar} = something
Here, a Foo object is just a blessed hash reference. Outside its class it behaves just as a normal
hash reference. Its Foo attributes can be retrieved or set only via methods.
Note that the attribute container doesn't need to be of the same type as the object. The object could be a scalar reference (or an anonymous subroutine) and still have a hash magically attached.