Полезная информация

Perl Cookbook

Perl CookbookSearch this book
Previous: 10.12. Handling ExceptionsChapter 10
Subroutines
Next: 10.14. Redefining a Function
 

10.13. Saving Global Values

Problem

You need to temporarily save away the value of a global variable.

Solution

Use the local operator to save a previous global value, automatically restoring it when the current block exits:

$age = 18;          # global variable
if (CONDITION) {
    local $age = 23;
    func();         # sees temporary value of 23
} # restore old value at block exit

Discussion

Unfortunately, Perl's local operator does not create a local variable. That's what my does. Instead, local merely preserves an existing value for the duration of its enclosing block. Hindsight shows that if local had been called save_value instead, much confusion could have been avoided.

Still, there are three places where you must use local instead of my:

  1. You need to give a global variable a temporary value, especially $_.

  2. You need to create a local file or directory handle or a local function.

  3. You want to temporarily change just one element of an array or hash.

Using local( ) for temporary values for globals

The first situation is more apt to happen with predefined, built-in variables than it is with user variables. These are often variables that Perl will use as hints for its high-level operations. In particular, any function that uses $_, implicitly or explicitly, should certainly have a local $_. This is annoyingly easy to forget to do. See Recipe 13.15 for one solution to this.

Here's an example of using a lot of global variables. The $/ variable is a global that implicitly affects the behavior of the readline operator used in <FH> operations.

$para = get_paragraph(*FH);        # pass filehandle glob 
$para = get_paragraph(\*FH);       # pass filehandle by glob reference
$para = get_paragraph(*IO{FH});    # pass filehandle by IO reference
sub get_paragraph {
    my $fh = shift;  
    local $/ = '';        
    my $paragraph = <$fh>;
    chomp($paragraph);
    return $paragraph;
} 

Using local( ) for local handles

The second situation arises when you need a local filehandle or directory handle, or, rarely, a local function. You can, in post 5.000 Perls, use one of the standard Symbol, Filehandle, or IO::Handle modules, but this simple typeglob technique still works. For example:

$contents = get_motd();
sub get_motd {
    local *MOTD;
    open(MOTD, "/etc/motd")        or die "can't open motd: $!";
    local $/ = undef;  # slurp full file;
    local $_ = <MOTD>;
    close (MOTD);
    return $_;
} 

If you wanted to return the open filehandle, you'd use:

return *MOTD;

Using local( ) on parts of aggregates

The third situation almost never occurs. Because the local operator is really a "save value" operator, you can use it to save off just one element of an array or hash, even if that array or hash is itself a lexical!

my @nums = (0 .. 5);
sub first { 
    local $nums[3] = 3.14159;
    second();
}
sub second {
    print "@nums\n";
} 
second();
0 1 2 3 4 5
first();
0 1 2 3.14159 4 5

The only common use for this kind of thing is for temporary signal handlers.

sub first {
    local $SIG{INT} = 'IGNORE';
    second();
} 

Now while second() is running, interrupt signals will be ignored. When first() returns, the previous value of $SIG{INT} will be automatically restored.

Although a lot of old code uses local, it's definitely something to steer clear of when it can be avoided. Because local still manipulates the values of global variables, not local variables, you'll run afoul of use strict.

The local operator produces dynamic scoping or run-time scoping. This is in contrast with the other kind of scoping Perl supports, which is much more intuitive. That's the kind of scoping that my provides, known as lexical scoping, or sometimes as static or compile-time scoping.

With dynamic scoping, a variable is accessible if it's in the current scope  - or the scope of any frames (blocks) in its subroutine call stack, as determined at run time. Any functions called have full access to dynamic variables, because they're still globals, just ones with temporary values. Only lexical variables are safe from tampering. If that's not enough reason to change, you might be interested to know that lexicals are about 10 percent faster to access than dynamics.

Old code that says:

sub func {
    local($x, $y) = @_;
    #....
} 

can almost always be replaced without ill effect by the following:

sub func {
    my($x, $y) = @_;
    #....
} 

The only case where code can't be so upgraded is when it relies on dynamic scoping. That would happen if one function called another, and the latter relied upon access to the former's temporary versions of the global variables $x and $y. Code that handles global variables and expects strange action at a distance instead of using proper parameters is fragile at best. Good programmers avoid this kind of thing like the plague.

If you come across old code that uses:

&func(*Global_Array);
sub func {
    local(*aliased_array) = shift;
    for (@aliased_array) { .... }
} 

this should probably be changed into something like this:

func(\@Global_Array);
sub func {
    my $array_ref  = shift;
    for (@$array_ref) { .... }
} 

They're using the old pass-the-typeglob strategy devised before Perl support proper references. It's not a pretty thing.

See Also

The local and my functions in Chapter 3 of Programming Perl and perlfunc (1); the section on "Subroutines" in Chapter 2 of Programming Perl; the sections on "Private Variables via my( )" "Temporary Values via local( )" in perlsub (1); Recipe 10.2; Recipe 10.16


Previous: 10.12. Handling ExceptionsPerl CookbookNext: 10.14. Redefining a Function
10.12. Handling ExceptionsBook Index10.14. Redefining a Function