Essentially, tie() allows you to associate a variable with a particular
class. Special methods are defined in a tied class that is implicitly
called whenever you access this variable. In the Digest::MD5 article
(Feb 2001), we tied an ordinary hash to a Berkeley DBM file, thus our
hash acted as a persistent database on disk. All the magic of storing
and retrieving hash elements from the disk was encapsulated in the
DB_File module and was automatically performed whenever we assigned to
the hash or retrieved and element from the hash.
You can tie scalars, arrays, hashes, and filehandles by defining an
appropriate tied class implementing the behaviours you desire. A main
difference between a tied class and an ordinary class is that you must
use special names (in all caps) for the methods that will be magically
called when accessing a variable.
For a concrete example, let's say we want to have a variable that takes
on a random value from a list each time we use it. We will call the
class RandSelect (and thus define a module named RandSelect.pm). We
want to use this variable as in the following example:
#!/usr/bin/perl -w
use strict;
use RandSelect;
tie my $rand, 'RandSelect', qw(andrew greg brad john);
print "The first six random selections are:\n";
print $rand, "\n" for 1..6;
This might print out (in one particular run):
The first six random selections are:
andrew
greg
john
john
andrew
brad
First, we need to create our tied class. Our class begins in the normal
fashion:
package RandSelect;
use strict;
Things change after this. The constructor for a tied scalar variable
class is called TIESCALAR, and its first argument (like class methods
in general) will be the class name:
sub TIESCALAR {
my $class = shift;
return bless [@_], $class;
}
That's the entire constructor: We grab the class name and then we
return a blessed anonymous array containing the remaining arguments
passed to the call to the tie() function. We also need to create the
method that will be called when we retrieve the value of a tied
variable (named FETCH), and the one that will be called when we assign
to a tied variable (named STORE). Each of this is an ordinary method
call that will receive the object itself as the first argument, and
then any remaining arguments (if any).
Even though we've tied a scalar variable, our object is really an array
reference, so that's what we deal with when trying to fetch and store
values:
sub FETCH {
my $self = shift;
return $self->[rand @$self];
}
sub STORE {
my $self = shift;
@$self = @{shift()};
}
1;
__END__
Our FETCH routine merely returns a random element from the array
reference, and the STORE routine expects an array reference and stores
a copy of it in the object. We finish off our module with a single
statement returning a true value (just '1;') and that completes the
entire tied scalar class. (we really should provide some error checking
to ensure an array reference is passed to STORE, but that is an
exercise for the reader).
There is already a module on CPAN (Tie::Pick) that is similar to the
above but removes each element as it is chosen from the list.
Tieing a scalar is the simplest kind of tied variable to create, but
many more methods exist that you need to define for tieing arrays and
hashes. Further information on tie and creating tied classes can be
found in the following Perl documentation pages:
perldoc -f tie
perldoc perltie
perldoc Tie::Scalar
perldoc Tie::Array
perldoc Tie::Hash
perldoc Tie::Handle
One final note: There is a bug in Perl 5.6.1 that sometimes causes a
tied variable to be accessed twice when it is interpolated -- that is
why in the example above I used 'print $rand, "\n"' instead of the
simpler 'print "$rand\n"'. This bug should be fixed in 5.6.2.
Next Week: Subroutine references