Introduction to mod_perl (part 4): Perl Basics - The Scope of the Special Perl Variables (
Page 7 of 9 )
Now let's talk about Special Perl Variables.
Special Perl variables like $| (buffering), $^T (script's start
time), $^W (warnings mode), $/ (input record separator), $\
(output record separator) and many more are all true global variables;
they do not belong to any particular package (not even main::) and
are universally available. This means that if you change them, you
change them anywhere across the entire program; furthermore you cannot
scope them with my(). However you can local()ise them which means that
any changes you apply will only last until the end of the enclosing
scope. In the mod_perl situation where the child server doesn't
usually exit, if in one of your scripts you modify a global variable
it will be changed for the rest of the process' life and will affect
all the scripts executed by the same process. Therefore localising
these variables is highly recommended, I'd say mandatory.
I will demonstrate the case on the input record separator variable. If
you undefine this variable, the diamond operator (readline) will suck
in the whole file at once if you have enough memory. Remembering this
you should never write code like the example below.
$/ = undef; # BAD!
open IN, "file" ....
# slurp it all into a variable
$all_the_file = <IN>;
The proper way is to have a local() keyword before the special
variable is changed, like this:
local $/ = undef;
open IN, "file" ....
# slurp it all inside a variable
$all_the_file = <IN>;
But there is a catch. local() will propagate the changed value to the
code below it. The modified value will be in effect until the script
terminates, unless it is changed again somewhere else in the script.
A cleaner approach is to enclose the whole of the code that is
affected by the modified variable in a block, like this:
{
local $/ = undef;
open IN, "file" ....
# slurp it all inside a variable
$all_the_file = <IN>;
}
That way when Perl leaves the block it restores the original value of
the $/ variable, and you don't need to worry elsewhere in your
program about its value being changed here.
Note that if you call a subroutine after you've set a global variable
but within the enclosing block, the global variable will be visible
with its new value inside the subroutine.