MySQL and Perl for the Web: Chapter 3 Section 3 (4/6)
[previous][next] |
Improving Performance with mod_perl
Variable Scope Effects
mod_perl
runs scripts by wrapping them inside a function (one reason for this is that it can assign each script its own unique namespace). This can cause problems due to variable scope. Here is a simple program that illustrates the effect:
#! /usr/bin/perl -w
print "Content-Type: text/html\n\n";
my $x = 0;
f ();
exit (0);
sub f
{
print $x++, "\n";
}
If you request this script several times from your browser, the script doesn't print 0 each time as you would expect. Instead, the values increase. This occurs even though the variable $x
is explicitly initialized to 0. A clue that something is wrong here will be found in the Apache error log:
Variable "$x" will not stay shared at line 5.
(The line number is off due to the script being executed inside the wrapper function.) The difficulty here is that when the script is run inside a wrapper by mod_perl
, your entire script becomes a single function, and any functions in the script become inner subroutines. That means f()
is an inner subroutine that references a lexically scoped my()
variable belonging to its parent subroutine and that isn't passed to it as an argument. As a result, the inner subroutine sees $x
with the correct value the first time the script runs. After that, the variable becomes unshared and the inner subroutine continues to use its own unshared value of $x
on subsequent invocations. This issue is discussed in more detail in the mod_perl
Guide, along with various solutions to the problem. One way to avoid the difficulty is to change the declaration of $x
to be global:
#! /usr/bin/perl -w
print "Content-Type: text/html\n\n";
use vars qw($x);
$x = 0;
f ();
exit (0);
sub f
{
print $x++, "\n";
}
You can declare a variable using my
if you want to, as long as you pass it as an argument to any subroutine that needs it, instead of accessing it directly from the subroutine as a global variable. (That's actually the way I prefer to write scripts, which is why you won't see many instances of use vars
in this book.) If you want to modify the variable inside the subroutine, pass it by reference:
#! /usr/bin/perl -w
print "Content-type: text/html\n\n";
my $x = 0;
f (\$x);
exit (0);
sub f
{
my $x_ref = shift;
print ++${$x_ref}, "\n";
}
[previous][next] |
Created: July 13, 2001
Revised: July 13, 2001