EDIT:
I use used bareword filehandles.
In the course of this discussion I was convinced not to do so.
I've seen many Perl programmers advocating the usage of lexical scalars instead.
Though there are good reasons for this, it has a drawback.
Filehandles in Perl are special on a syntactical level.
The compiler is capable of catching errors like this:
open FH, '<', 'myfile';
print FH, "something\n";
by emitting an error:
No comma allowed after filehandle at ...
Whereas strange things happen at runtime if you use:
open my $fh, '<', 'myfile';
print $fh, "something\n";
NB: Someone else pointed to this subtle difference but sadly I don't remember who and where it was.
She/he should be credited here.
So I stay with barewords and try to avoid the problems caused by the usage of global variables using this idiom:
open local *FH, '<', 'myfile';
while (<FH>) {
# do something
}
close FH;
Some features:
- usages of equally named file handles do not affect each other in different scopes
- the usage in a sub does no harm if the sub is in the same package and it uses the same idiom
- the usage in a sub of a different package does not harm.
So, as long as I follow this pattern im my own package, I feel kind of safe.
Side effects of localizing a glob are easily circumvented.
The question remains: Do I miss something here?
Do you see any pitfalls using this approach?
Here is an example demonstrating the issues I'm aware of.
#!/usr/bin/perl
use Test2::V0;
package Foobar;
our $foobar = "foobar\n";
our @foobar;
sub use_fh {
# unlocalized use of FH in separate package
open FH, '<', \$foobar;
@foobar = <FH>;
close FH;
}
package main;
my $foo = "foo\n";
my $bar = "bar\n";
my $baz = "baz\n";
my @baz;
sub use_localized_fh {
# protect caller's FH
open local *FH, '<', \$baz;
@baz = <FH>;
close FH;
}
sub close_fh {
# unlocalized use of FH
close FH;
}
# open now, use later
open FH, '<', \$bar;
my @foo;
# create new scope
{
# use localized FH, protecting handle opened on \$bar
open local *FH, '<', \$foo;
# call sub that uses localized FH
use_localized_fh;
# call sub in other package that uses FH
Foobar::use_fh;
# FH still intact
@foo = <FH>;
close FH;
}
is \@baz, [$baz], 'got $baz in sub';
is \@Foobar::foobar, [$Foobar::foobar], 'got $Foobar::foobar in foreig
+n sub';
is \@foo, [$foo], 'good: got $foo';
{
open local *FH, '<', \$foo;
# call sub that closes FH
close_fh;
@foo = <FH>;
close FH;
}
is \@foo, [], 'bad: FH was closed in sub';
# FH at this scope is still untouched
my @bar = <FH>;
close FH;
is \@bar, [$bar], 'good: got $bar';
done_testing;
Greetings,
-jo
$gryYup$d0ylprbpriprrYpkJl2xyl~rzg??P~5lp2hyl0p$