With the exception of regexps, you need to pass references to these objects.
See Pass
by Reference for this particular question, and the
perlref manpage for information on references.
- Passing Variables and Functions
-
Regular variables and functions are quite easy: just pass in a reference
to an existing or anonymous variable or function:
func( \$some_scalar );
func( \@some_array );
func( [ 1 .. 10 ] );
func( \%some_hash );
func( { this => 10, that => 20 } );
func( \&some;_func );
func( sub { $_[0] ** $_[1] } );
- Passing Filehandles
-
To pass filehandles to subroutines, use the *FH
or \*FH
notations. These are ``typeglobs'' - see Typeglobs
and Filehandles and especially Pass
by Reference for more information.
Here's an excerpt:
If you're passing around filehandles, you could usually just use the bare
typeglob, like *STDOUT, but typeglobs references
would be better because they'll still work properly under use strict
'refs'
. For example:
splutter(\*STDOUT);
sub splutter {
my $fh = shift;
print $fh "her um well a hmmm\n";
}
$rec = get_rec(\*STDIN);
sub get_rec {
my $fh = shift;
return scalar <$fh>;
}
If you're planning on generating new filehandles, you could do this:
sub openit {
my $name = shift;
local *FH;
return open (FH, $path) ? *FH : undef;
}
$fh = openit('< /etc/motd');
print <$fh>;
- Passing Regexps
-
To pass regexps around, you'll need to either use one of the highly
experimental regular expression modules from CPAN
(Nick Ing-Simmons's Regexp or Ilya Zakharevich's Devel::Regexp), pass around
strings and use an exception-trapping eval, or else be very, very clever.
Here's an example of how to pass in a string to be regexp compared:
sub compare($$) {
my ($val1, $regexp) = @_;
my $retval = eval { $val =~ /$regexp/ };
die if $@;
return $retval;
}
$match = compare("old McDonald", q/d.*D/);
Make sure you never say something like this:
return eval "\$val =~ /$regexp/"; # WRONG
or someone can sneak shell escapes into the regexp due to the double
interpolation of the eval and the double-quoted string. For example:
$pattern_of_evil = 'danger ${ system("rm -rf * &") } danger';
eval "\$string =~ /$pattern_of_evil/";
Those preferring to be very, very clever might see the O'Reilly book, Mastering
Regular Expressions, by Jeffrey Friedl. Page 273's Build_MatchMany_Function()
is particularly interesting. A complete citation of this book is given in the
perlfaq2 manpage.
- Passing Methods
-
To pass an object method into a subroutine, you can do this:
call_a_lot(10, $some_obj, "methname")
sub call_a_lot {
my ($count, $widget, $trick) = @_;
for (my $i = 0; $i < $count; $i++) {
$widget->$trick();
}
}
Or you can use a closure to bundle up the object and its method call and
arguments:
my $whatnot = sub { $some_obj->obfuscate(@args) };
func($whatnot);
sub func {
my $code = shift;
&$code();
}
You could also investigate the can()
method in the UNIVERSAL
class (part of the standard perl distribution).