Приглашаем посетить
Гоголь (gogol-lit.ru)

Section 14.4.  Using AUTOLOAD for Accessors

Previous
Table of Contents
Next

14.4. Using AUTOLOAD for Accessors

Chapter 12 showed how to create color and set_color to get and set the color of an animal. If we had 20 attributes instead of 1 or 2, the code would be painfully repetitive. However, using an AUTOLOAD method, we can construct the nearly identical accessors as needed, saving both compilation time and wear-and-tear on the developer's keyboard.

We use a code reference as a closure to do the job. First, we set up an AUTOLOAD for the object and define a list of hash keys for which we want trivial accessors:

sub AUTOLOAD {
  my @elements = qw(color age weight height);

Next, we'll see if the method is a getter for one of these keys, and, if so, we install a getter and jump to it:

our $AUTOLOAD;
if ($AUTOLOAD =~ /::(\w+)$/ and grep $1 eq $_, @elements) {
  my $field = ucfirst $1;
  {
    no strict 'refs';
    *{$AUTOLOAD} = sub { $_[0]->{$field} };
  }
  goto &{$AUTOLOAD};
}

We need to use ucfirst because we named the method color to fetch the hash element called Color. The glob notation here installs a wanted subroutine as defined by the coderef closure, which fetches the corresponding key from the object hash. Consider this part to be magic that we just cut and paste into our program. Finally, the goto construct jumps into the newly defined subroutine.

Otherwise, perhaps it's a setter:

if ($AUTOLOAD =~ /::set_(\w+)$/ and grep $1 eq $_, @elements) {
  my $field = ucfirst $1;
  {
    no strict 'refs';
    *{$AUTOLOAD} = sub { $_[0]->{$field} = $_[1] };
  }
  goto &{$AUTOLOAD};
}

If it is neither, death awaits:

croak "$_[0] does not understand $method\n";
  }

Again, we pay the price for the AUTOLOAD only on the first hit of a particular getter or setter. After that, a subroutine is now already defined, and we can just invoke it directly.


Previous
Table of Contents
Next