| home / programming / perl / mod_perl / chap6 / 1 | [previous] [next] |
|
|
Example 6-3: Book/Counter.pm
package Book::Counter;my $counter = 0;sub run {$counter = 0;for (1..5) {increment_counter( );}}sub increment_counter {$counter++;print "Counter is equal to $counter !<BR>\n";}1;_ _END_ _
Example 6-4: counter-clean.pl
use strict;use Book::Counter;print "Content-type: text/plain\n\n";Book::Counter::run( );
As you can see, the only difference is in the package declaration. As long as the package name is unique, you won't encounter any collisions with other scripts running on the same server.
Another solution to this problem is to change the lexical variables to global variables. There are two ways global variables can be used:
vars pragma. With
the use strict 'vars' setting, global variables
can be used after being declared with vars. For
example, this code:
use strict;use vars qw($counter $result);# later in the code$counter = 0;$result = 1;
is similar to this code if use
strict is not used:
$counter = 0;$result = 1;
However, the former style of coding is much cleaner, because it allows you to use global variables by declaring them, while avoiding the problem of misspelled variables being treated as undeclared globals.
The only drawback to using vars
is that each global declared with it consumes more memory than the undeclared
but fully qualified globals, as we will see in the next item.
$counter,
we can use $Foo::counter, which will place the
global variable $counter into the package Foo.
Note that we don't know which package name Apache::Registry
will assign to the script, since it depends on the location from which the
script will be called. Remember that globals must always be initialized before
they can be used.Perl 5.6.x also introduces a third way, with the our(
) declaration. our( ) can be used in different
scopes, similar to my( ), but it creates global
variables.
Finally, it's possible to avoid this problem altogether by always passing the variables as arguments to the functions (see Example 6-5).
Example 6-5: counter2.pl
#!/usr/bin/perl -wuse strict;print "Content-type: text/plain\n\n";my $counter = 0;for (1..5) {$counter = increment_counter($counter);}sub increment_counter {my $counter = shift;$counter++;print "Counter is equal to $counter !\n";return $counter;}
In this case, there is no variable-sharing problem. The drawback
is that this approach adds the overhead of passing and returning the variable
from the function. But on the other hand, it ensures that your code is doing
the right thing and is not dependent on whether the functions are wrapped in
other blocks, which is the case with the Apache::Registry
handlers family.
When Stas (one of the authors of this book) had just started using mod_perl and wasn't aware of the nested subroutine problem, he happened to write a pretty complicated registration program that was run under mod_perl. We will reproduce here only the interesting part of that script:
use CGI;$q = CGI->new;my $name = $q->param('name');print_response( );sub print_response {print "Content-type: text/plain\n\n";print "Thank you, $name!";}
Stas and his boss checked the program on the development server and it worked fine, so they decided to put it in production. Everything seemed to be normal, but the boss decided to keep on checking the program by submitting variations of his profile using The Boss as his username. Imagine his surprise when, after a few successful submissions, he saw the response "Thank you, Stas!" instead of "Thank you, The Boss!"
After investigating the problem, they learned that they had been hit by the nested subroutine problem. Why didn't they notice this when they were trying the software on their development server? We'll explain shortly.
To conclude this first mystery, remember to keep the warnings
mode On on the development server and to watch
the error_log file for
warnings.
| home / programming / perl / mod_perl / chap6 / 1 | [previous] [next] |
Created: March 27, 2003
Revised: July 23, 2003
URL: http://webreference.com/programming/perl/mod_perl/chap6/1