There are two major variable types in Perl. One of them is the package global variable declared either with the now obsolete use vars construct or with our.

The other one is the lexical variable declared with my.

Let's see what happens when you declare a variable using my? In which parts of the code will that variable be visible? In other words, what is the scope of the variable?

Variable scope: enclosing block

#!/usr/bin/perl
use strict;
use warnings;

{
    my $email = 'foo@bar.com';
    print "$email\n";     # foo@bar.com
}
# print $email;
# $email does not exists
# Global symbol "$email" requires explicit package name at ...

Inside the anonymous block (the pair of curly braces {}), first we see the declaration of a new variable called $email. This variable exists between the point of its declaration till the end of the block. Thus the line after the closing curly brace } had to be commented out. If you removed the # from the # print $email; line, and tried to run the script, you'd get the following compile-time error: Global symbol "$email" requires explicit package name at ....

In other words, the scope of every variable declared with my is the enclosing block..

Variable scope: visible everywhere

The variable $lname is declared at the beginning of the code. It will be visible till the end of the file everywhere. Even inside blocks. Even if those are function declarations. If we change the variable inside the block, that will change the value for the rest of the code. Even when you leave the block:

#!/usr/bin/perl
use strict;
use warnings;

my $lname = "Bar";
print "$lname\n";        # Bar

{
    print "$lname\n";    # Bar
    $lname = "Other";
    print "$lname\n";    # Other
}
print "$lname\n";        # Other

Variable hidden by other declaration

#!/usr/bin/perl
use strict;
use warnings;

my $fname = "Foo";
print "$fname\n";        # Foo

{
    print "$fname\n";    # Foo

    my $fname  = "Other";
    print "$fname\n";    # Other
}
print "$fname\n";        # Foo

In this case the variable $fname is declared at the beginning of the code. As written earlier, it will be visible till the end of the file everywhere, except in places where they are hidden by locally declared variables with the same name.

Inside the block we used my to declare another variable with the same name. This will effectively hide the $fname declared outside the block till we leave the block. At the end of the block (at the closing }), the $fname declared inside will be destroyed and the original $fname will be accessible again. This feature is especially important as this makes it easy to create variables inside small scopes without the need to think about possible use of the same name outside.

Same name in multiple blocks

You can freely use the same variable name in multiple block. These variables have no connection to each other.

#!/usr/bin/perl
use strict;
use warnings;

{
    my $name  = "Foo";
    print "$name\n";    # Foo
}
{
    my $name  = "Other";
    print "$name\n";    # Other
}

in-file package declaration

This a bit more advanced example, but it might be important to mention it here:

Perl allows us to switch between name-spaces using the package keyword inside a file. A package declaration does NOT provide scope. If you declare a variable in the implicit main package which is just the regular body of your script, that $fname variable will be visible even in other name-spaces in the same file.

If you declare a variable called $lname in the 'Other' name-space, it will be visible when later you might switch back to the main name-space. If the package Other declaration was in another file, then the variables would have separate scope created by the file.

#!/usr/bin/perl
use strict;
use warnings;

my $fname  = "Foo";
print "$fname\n";    # Foo

package Other;
use strict;
use warnings;

print "$fname\n";    # Foo
my $lname = 'Bar';
print "$lname\n";    # Bar


package main;

print "$fname\n";    # Foo
print "$lname\n";    # Bar