#!/bin/perl -w use strict; package invalid; our $protected; # class1 => method_a => 1 # => method_b => 1 # class2 ... our $AUTOLOAD; # called by the package using the protection # methods to protect are stored for each class sub init { my( $class, $class_to_protect, @methods_to_protect)= @_; my %methods_to_protect=map { ($_, 1) } @methods_to_protect; $protected->{$class_to_protect} = \%methods_to_protect; } # an invalid object stores the cass of the original object sub new { my( $class, $obj)= @_; return bless { class => ref $obj}, $class; } # obviously it is not valid, that's the whole point! sub is_valid { return undef; } # return the invalid object or undef sub AUTOLOAD { my $invalid= shift; my $method= ( split /::/, $AUTOLOAD)[-1]; # get the method from $AUTOLOAD my $class= $invalid->{class}; # the original class from the object if( $protected->{$class}->{$method}) { return $invalid; } # protected method else { return undef; } # unprotected one } package foo; # need to pass the list of methods to protect BEGIN { invalid->init( __PACKAGE__, qw( kid)); } sub new { my( $class, $value)= @_; return bless { value => $value}, $class; } sub add_kid { my( $self, $kid)= @_; $self->{kid}= $kid; } sub value { my $self= shift; return $self->{value}; } sub kid { my $self= shift; return $self->{kid} if( $self->{kid}); return invalid->new( $self); # do not return undef but an invalid object } sub is_valid { return $_[0]; } package main; my $parent= foo->new( 'parent'); my $kid= foo->new( 'kid'); $parent->add_kid( $kid); print "foo:\n"; print " parent: ", $parent->value || '', "\n"; print " parent->kid: ", $parent->kid->value || '', "\n"; print " parent->kid->kid: ", $parent->kid->kid->value || '', "\n"; print " parent->kid->kid->kid: ", $parent->kid->kid->kid->value || '', "\n\n";