Which one is good practice, a lexical filehandle or a typeglob?
Some say we should use a lexical filehandle instead of a typeglob, like this:
open $fh, $filename;
But 开发者_如何学Gomost Perl books, including The Llama Book, use a typeglob, like this:
open LOGFILE, $filename;
So what are the differences? Which one is considered a better practice?
The earliest edition of the Llama Book is from 1993, before lexical filehandles were part of the Perl language. Lexical filehandles are a better practice for a variety of reasons. The most important disadvantages of typeglobs are
they are always global in scope, which can lead to insidious bugs like this one:
sub doSomething { my ($input) = @_; # let's compare $input to something we read from another file open(F, "<", $anotherFile); @F = <F>; close F; do_some_comparison($input, @F); } open(F, "<", $myfile); while (<F>) { doSomething($_); # do'h -- just closed the F filehandle } close F;
they are harder to pass to a subroutine than a lexical filehandle
package package1; sub log_time { # print timestamp to filehandle my ($fh) = @_; print $fh scalar localtime, "\n"; } package package2; open GLOB, '>', 'log1'; open $lexical, '>', 'log2'; package1::log_time($lexical); # works as expected package1::log_time(GLOB); # doesn't work package1::log_time('GLOB'); # doesn't work package1::log_time(*GLOB); # works package1::log_time(package2::GLOB); # works package1::log_time('package2::GLOB'); # works
See also: Why is three-argument open calls with autovivified filehandles a Perl best practice?
When lexical variables are used, the filehandles have the scope of these variables and are automatically closed whenever you leave that scope:
{
open my $fh, '<', 'file' or die $!;
# ...
# the fh is closed upon leaving the scope
}
So you do not create permanent global variables.
Lexical filehandles can be passed easily as arguments, filehandles cannot. Typeglobs can (or at least references to them can), but that's kinda messy. Consider sticking with lexical variables, and make sure to declare them first, so you know that they're really lexical and not local or global. I.e.
my $fh;
open $fh, $filename;
Also consider using IO::Handle
or IO::File
as options. Used to be FileHandle
but was informed by ysth below that FileHandle
now just uses 'IO::Handle' in turn, which is news to me since 5.6, but there's a lot to learn here. :-)
Also, don't forget use strict
:-)
Usage of typeglob filehandle is not recommended because if you don't pay attention, this can lead to several issues. E.g: If you're creating a recursive function which reuses the same typeglob, you'll get some warnings when you try to close the filehandle unless you create a temporal-limited package-based glob. Lexical variables are scoped to the block in which they are defined while the typeglob scope is for the full package in which it is defined.
To resume:
If you want stay with typeglob filehandle make sure to create a temporal-limited package-based glob:
...
local *FH;
open FH, '<', $filepath or die(sprintf('Could not open %s: %s', $filepath, $!));
...
else, use a lexical variable
...
open my $fh, '<', $filepath or die(sprintf('Could not open %s: %s', $filepath, $!));
...
精彩评论