NAME
Class::Property - Perl implementation of class properties.
VERSION
Version v1.0.1
SYNOPSIS
This module allows you to easily create properties for your class. It supports default, custom and lazy properties. Basically, properties are just a fancy way to access object's keys, generally means $foo->some_property
is equal to $foo->{'some_property'}
.
General syntax:
package Foo;
use Class::Property;
property(
'name' => { 'get' => undef, 'set' => undef }, # creates default RW property, fastests
'age' => { 'get' => undef }, # creates default RO property
'salary' => { 'set' => undef }, # creates default WO property
'weight' => { 'get' => \&weight_getter, 'set' => undef }, # creates RW property with custom getter and default setter
'family' => { 'get_lazy' => \&read_family }, # creates RO property with lazy init method
);
After you've created properties for your class, you may use them as lvalues:
use Foo;
my $foo = Foo->new();
$foo->name = 'Yourname';
printf 'The age of %s is %s', $foo->name, $foo->age;
Usually you'll need to use general syntax when you want to use custom getters/setters and/or lazy properties. To make your code cleaner, there are few helper methods:
rw_property( 'street', 'house', 'flat' ); # creates 3 RW properties
ro_property( 'sex', 'height' ); # creates 2 RO properties
wo_property( 'relation' ); # creates WO property
API
Default properties
Default properties are the fastest way to make your code cleaner. They just mapping object's hash keys to class methods and returns them as lvalues. Just use:
rw_property( ... property names ... );
Read-only and write-only properties
Default RO and WO properties works slower, because they are using wrapper class, but they control access to the object properties. Both croaks on attempt to write to RO property or read WO one. Currently, perl doesn't allow to restrict access to the object hash keys, but you will use only properties in your code, you'll have additional control. You may create such properties with helper methods:
ro_property( ... property names ... );
# or
wo_property( ... property names ... );
Custom getters/accessors
Sometimes you need to do something special on reading property, count reads, for example. This may be done via custom getter:
property( 'phone_number' => {'get' => \&my_getter, 'set' => undef} );
sub my_getter
{
my($self) = @_;
$self->{'somecounter'}++;
return $self->{'phone_number'};
}
The property above will use default way to set data and call your own method to get it. Custom getter being invoked as object method (with $self
passed) and it must return requested value.
Custom setters/mutators
Sometimes you need to do something special on writing property, validate, for example. This may be done via custom setter:
property( 'phone_number' => {'get' => undef, 'set' => \&my_setter} );
sub my_setter
{
my($self, $value) = @_;
... validation or exception is here...
$self->{'phone_number'} = $value;
return;
}
The property above will use default way to get data and call your own method to set it. Custom setter being invoked with two arguments - reference to an object and value to set. Setter responsible to store data in proper place.
Lazy properties
Lazy properties may be useful in situations, when reading data is resourseful or slow and it may be never used in current piece of code. For example, you may have database with persons and their relations:
package Person;
use Class::Property;
property(
'family' => { 'get_lazy' => \&read_family, 'set' => undef },
);
sub read_family
{
my($self) = @_;
... reading family members from database...
return $family;
}
...
my $me = Person->new(...);
my $family = $me->family; # first occurance, invokes read_family in background (resourceful)
print_family( $me->family ); # other occurances, takes family from default place (fast)
Such class will have a lazy property: family
. If some code will try to access this object's property a first time, your method read_family
will be invoked and it's result will be stored in default place. Further accesses won't invoke init function, property will behave as non-lazy.
BENCHMARKING
Here is a comparision of different properties and alternatives as Class::Accessor
and Class::Accessor::Fast
1. Direct hash read : 1 wallclock secs ( 0.75 usr + 0.00 sys = 0.75 CPU) @ 13351134.85/s (n=10000000)
2. Direct hash write : 1 wallclock secs ( 0.73 usr + 0.00 sys = 0.73 CPU) @ 13642564.80/s (n=10000000)
3. Class::Property rw read : 3 wallclock secs ( 2.50 usr + 0.00 sys = 2.50 CPU) @ 4006410.26/s (n=10000000)
4. Class::Property rw write : 3 wallclock secs ( 2.21 usr + 0.00 sys = 2.21 CPU) @ 4516711.83/s (n=10000000)
5. Class::Property lrw read : 2 wallclock secs ( 2.32 usr + 0.00 sys = 2.32 CPU) @ 4302925.99/s (n=10000000)
6. Class::Property lrw write : 3 wallclock secs ( 2.14 usr + 0.00 sys = 2.14 CPU) @ 4677268.48/s (n=10000000)
7. Class::Accessor::Fast read : 3 wallclock secs ( 3.28 usr + 0.00 sys = 3.28 CPU) @ 3052503.05/s (n=10000000)
8. Class::Accessor::Fast write: 4 wallclock secs ( 3.87 usr + 0.00 sys = 3.87 CPU) @ 2585315.41/s (n=10000000)
9. Class::Accessor read : 7 wallclock secs ( 6.41 usr + 0.00 sys = 6.41 CPU) @ 1559819.06/s (n=10000000)
10. Class::Accessor write : 8 wallclock secs ( 7.85 usr + 0.01 sys = 7.86 CPU) @ 1271940.98/s (n=10000000)
11. Class::Property ro read : 37 wallclock secs (36.22 usr + 0.00 sys = 36.22 CPU) @ 276067.69/s (n=10000000)
12. Class::Property wo write : 36 wallclock secs (35.96 usr + 0.00 sys = 35.96 CPU) @ 278102.23/s (n=10000000)
13. Class::Property crw read : 40 wallclock secs (39.83 usr + 0.02 sys = 39.84 CPU) @ 250985.12/s (n=10000000)
14. Class::Property crw write : 40 wallclock secs (41.73 usr + 0.00 sys = 41.73 CPU) @ 239635.75/s (n=10000000)
We can see, that default properties and default lazy properties are fastest and works 3 times slower than direct accessing to hash elements. Custom properties (RO, WO with custom getters and/or setters) are really slow, about 50 times slower, than direct access.
BUGS AND IMPROVEMENTS
If you found any bug and/or want to make some improvement, feel free to participate in the project on GitHub: https://github.com/hurricup/Class-Property
LICENSE
This module is published under the terms of the MIT license, which basically means "Do with it whatever you want". For more information, see the LICENSE file that should be enclosed with this distributions. A copy of the license is (at the time of writing) also available at http://www.opensource.org/licenses/mit-license.php.
SEE ALSO
Main project repository and bugtracker: https://github.com/hurricup/Class-Property
See also: Class::Accessor, Class::Accessor::Fast.
AUTHOR
Copyright (C) 2015 by Alexandr Evstigneev (hurricup@evstigneev.com)