NAME
Class::Accessor - Automated accessor generation
SYNOPSIS
package Foo;
use base qw(Class::Accessor);
use public qw(this that whatever);
sub new { return bless {} }
# Meanwhile, in a nearby piece of code!
my $foo = Foo->new;
my $whatever = $foo->whatever; # gets $foo->{whatever}
$foo->this('likmi'); # sets $foo->{this} = 'likmi'
# Similar to @values = @{$foo}{qw(that whatever)}
@values = $foo->get(qw(that whatever));
# sets $foo->{that} = 'crazy thing'
$foo->set('that', 'crazy thing');
DESCRIPTION
This module automagically generates accessors for all public fields of a subclass.
Most of the time, writing accessors is an exercise in cutting and pasting. You usually wind up with a series of methods like this:
# accessor for $obj->{foo}
sub foo {
my($self) = shift;
if(@_ == 1) {
$self->{foo} = shift;
}
elsif(@_ > 1) {
$self->{foo} = [@_];
}
return $self->{foo};
}
# accessor for $obj->{bar}
sub bar {
my($self) = shift;
if(@_ == 1) {
$self->{bar} = shift;
}
elsif(@_ > 1) {
$self->{bar} = [@_];
}
return $self->{bar};
}
# etc...
One for each piece of data in your object. While some will be unique, doing value checks and special storage tricks, most will simply be exercises in repetition. Not only is it Bad Style to have a bunch of repetitious code, but its also simply not Lazy, which is the real tragedy.
If you make your module a subclass of Class::Accessor and declare all your public data members using either the public or fields modules, then you'll find yourself with a set of automatically generated autoloaders which can even be customized!
The basic set up is very simple:
package My::Class;
use base qw(Class::Accessor);
use public qw(foo bar car);
Done. My::Class now has simple foo(), bar() and car() accessors defined.
The rest is details.
DETAILS
An accessor generated by Class::Accessor looks something like this:
# Your foo may vary.
sub foo {
my($self) = shift;
if(@_) { # set
return $self->set('foo', @_);
}
else {
return $self->get('foo', @_);
}
}
Very simple. All it does is determine if you're wanting to set a value or get a value and calls the appropriate method. Class::Accessor provides default get() and set() methods which your class can override. They're detailed later.
The accessor autoloader
Class::Accessor employs an autoloader to get its job done. Just set the record straight there is -no- performance penalty from the autoloader after the first accessor method call. Only the first call to each accessor hits the autoloader where it is defined as a perfectly normal static method (actually, its a closure.)
Modifying the behavior of the accessor
Rather than actually modifying the accessor itself, it is much more sensible to simply override the two key methods which the accessor calls. Namely set() and get().
If you -really- want to, you can override make_accessor().
- set
-
$obj->set($key, $value); $obj->set($key, @values);
set() defines how generally one stores data in the object.
- get
-
$value = $obj->get($key); @values = $obj->get(@keys);
- make_accessor
-
$accessor = Class->make_accessor($field);
Generates a subroutine reference which acts as an accessor for the given $field.
- make_static_accessors
-
Class->make_static_accessors; Class->make_static_accessors(@fields);
This will bypass the autoloader and immediately generate accessors. Useful for certain situations. "CAVEATS AND TRICKS".
If called with no arguments it will generate accessors for every public field in the Class. Otherwise it will just create accessors for those @fields given (irregardless of their status as fields!)
Foreach field in @fields it will generate two accessors. One called "field()" and the other called "_field_accessor()". For example:
# Generates foo(), _foo_accessor(), bar() and _bar_accessor(). Class->make_static_accessors(qw(foo bar));
CAVEATS AND TRICKS
Class::Accessor has to do some internal wackiness to get its job done quickly and efficiently. Because of this, there's a few tricks and traps one must know about.
Hey, nothing's perfect.
Don't make a public field called DESTROY
This is bad. Since DESTROY is a magical method it would be bad for us to define an accessor using that name. Class::Accessor will choke if you try to use it with a public field named "DESTROY".
can() cannot
Normally, one would expect $obj->can('foo') to see if $obj has a method called 'foo' defined. Unfortunately can() doesn't work well when autoloaders are involved, and Class::Accessor involves an autoloader. For efficiency's sake, Class::Accessor does not actually define the accessor method until it is first called. After that call the method is defined can can() will work. Before that, however, can() will not see an autogenerated accessor.
The simplest way around this is to call make_static_accessors(). As detailed before, this will force the generation of your accessors and allow can() to work normally.
Overriding autogenerated accessors
You may want to override the autogenerated accessor with your own, yet have your custom accessor call the default one. Normally, one would expect this to work:
package My::Class;
use base qw(Class::Accessor);
use public qw(foo);
sub foo {
my($self) = shift;
## Do some special work ##
# XXX THIS WILL NOT WORK. There is no SUPER::foo().
return $self->SUPER::foo(@_);
}
Unforunately, it doesn't. Class::Accessor employs an autoloader to inject methods directly into its subclass. This means there -is- no SUPER::foo(). As a simple hack around this, in addition to defining foo(), Class::Accessor will also define an alias as _foo_accessor().
So the correct way to override an autogenerated accessor is to use _foo_accessor().
package My::Class;
use base qw(Class::Accessor);
use public qw(foo);
sub foo {
my($self) = shift;
## Do some special work ##
# The correct way.
return $self->_foo_accessor(@_);
}
Providing your own autoloader.
Since Class::Accessor employs an autoloader which must be called, it would wreck some havok if your class defined its own autoloader. There's two simple ways around this.
First, you can simply bypass Class::Accessor's autoloader and have all your accessors generated at compile time:
package My::Class;
use base qw(Class::Accessor);
use public qw(foo bar yar car);
# All your accessors are now defined,
# Class::Accessor::AUTOLOAD() no longer enters the
# picture.
My::Class->make_static_accessors;
sub AUTOLOAD {
# whatever...
}
Or, you can have your autoloader call Class::Accessor::AUTOLOAD().
sub AUTOLOAD {
my($self) = $_[0];
#
# Do that autoloading thing.
#
# If all else fails, let Class::Accessor take a wack.
goto &Class::Accessor::AUTOLOAD;
}
You must, of course, be careful not to modify @_ or $AUTOLOAD.
AUTHOR
Michael G Schwern <schwern@pobox.com>