File handles are traditionally package variables that represent file descriptors. Unlike other variables, file handles are typically not prefixed with punctuation. All barewords are subject to being interpreted by the parser differently than the developer intended, but bareword filehandles file handles are particularly fraught with peril. Consequently, filehandles file handles should never be stored as barewords.
...
Suppose we maintain some simple code that makes the mistake of using bareword filehandlesfile handles.
Code Block | ||||
---|---|---|---|---|
| ||||
open( GOOD, "<", "good.txt"); my $good_data = <GOOD>; print "GOOD: $good_data"; print "\n"; { open( BAD, "<", "bad.txt"); my $bad_data = <BAD>; print "BAD: $bad_data"; print "\n"; } my $more_good_data = <GOOD>; print "MORE GOOD: $more_good_data"; |
This code works as expected. It reads and prints a line of good text, followed by a line of bad text, followed by a second line of good text.
But during maintainancemaintenance, someone (undoubtedly with the best of intentions) adds this function:
Code Block | ||||
---|---|---|---|---|
| ||||
sub BAD {return GOOD;} |
This function completely changes the behavior of the subsequent code. The BAD
bareword is now interpreted as a subroutine call, not a filehandlefile handle.
The program, as before, first opens good.txt
, storing it in the GOOD
filehandle file handle, which is a package variable. It then proceeds to open next opens bad.txt
, but instead of storing the descriptor in a BAD
filehandle file handle, it stores the descriptor in the filehandle file handle returned by the BAD()
subroutine. Which , which returns GOOD
. Consequently, the GOOD
filehandle file handle now points to the descriptor for bad.txt
, not good.txt
.
The program then tries to read from the BAD
filehandle file handle, but this attempted read produces nothing , since because this filehandle file handle was never actually opened. Nonetheless, the program then reads a line from the GOOD
filehandle, file handle and echoes it. Which it—which turns out to be from bad.txt
, rather than good.txt
.
Compliant Solution
This compliant solution protects the file descriptors by using anonymous scalars rather than bareword filehandlesfile handles.
Code Block | ||||
---|---|---|---|---|
| ||||
sub BAD {return GOOD;} open( my $GOOD, "<", "good.txt"); my $good_data = <$GOOD>; print "GOOD: $good_data"; print "\n"; { open( my $BAD, "<", "bad.txt"); my $bad_data = <$BAD>; print "BAD: $bad_data"; print "\n"; } my $more_good_data = <$GOOD>; print "MORE GOOD: $more_good_data"; |
Consequently, the original behavior of this program is restored. Because the $BAD
variable is declared with my
, it is a lexical variable , rather than a package variable . So it and is unaffected by the BAD
subroutine. So this program once again prints two lines from the good.txt
file , and one from the bad.txt
file, and never confuses the two.
Exceptions
FIO00:EX0: According to Jeffrey Thalhamer [CPAN/PerlCritic]:
There are three exceptions: STDIN, STDOUT and STDERR. These three standard filehandles are always package variables.
These bareword filehandles file handles may be used.
Risk Assessment
...
Tool | Diagnostic |
---|---|
Perl::Critic | InputOutput::ProhibitBarewordFileHandles |
Bibliography
...
"Filehandles," p. 202 | |
[ |
...
CPAN] |
...
Jeffrey Thalhammer, Perl-Critic-1. |
...
...