Which one is good practice, a lexical filehandle or a typeglob?

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

  1. 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;
    
  2. 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, $!));
...