Storing Filehandles into Variables (Perl Cookbook, 2nd Edition)

## 7.5. Storing Filehandles into Variables

### 7.5.1. Problem

You want to use a filehandle like a normal variable so you can pass it to or return it from a function, store it in a data structure, and so on.

### 7.5.2. Solution

The easiest way to get a filehandle into a variable is to have `open` put it there for you:

>     open(my $fh, "<", $filename)      or die "$0: can't open $filename: $!";

To store named filehandles into a variable or pass them into or out of a function, use typeglob notation (`*FH`):

>     $variable = *FILEHANDLE;        # save in variable
>     subroutine(*FILEHANDLE);        # or pass directly

>     sub subroutine {
>         my $fh = shift;
>         print $fh "Hello, filehandle!\n";
>     }

### 7.5.3. Discussion

If you pass an undefined scalar variable as the first argument to `open`, Perl allocates an anonymous typeglob and stores a reference to that typeglob in that scalar, effectively creating filehandles on demand. Like all other references, autovivified filehandles are subject to garbage collection, so this code doesn't leak a filehandle:

>     {
>         open(my $fh, "< /etc/motd") or die;
>         local $/;          # slurp mode
>         $text = <$fh>;
>     }

When Perl reaches the end of the block, `$fh` goes out of scope. As explained earlier in the Introduction, because that variable contained the last reference to the anonymous filehandle created by `open`, the variable is garbage collected and the filehandle implicitly closed.

Autovivified filehandles, being anonymous and already held in variables, don't help you to understand how to pass named filehandles as function parameters or store them in variables, including elements of arrays or hashes. By named filehandles, we mean those of the form `FH`, including all predefined handles, such as `STDIN` and `ARGV`. So let's look at what `FH` is and how to extract a scalar value from it to use for all of those things.

Named filehandles used in:

>     print STDERR "stuff\n";
>     $input = <STDIN>;
>     open(TTY, "+<", "/dev/tty");
>     if (eof(ARGV)) { .... }

are names, not variables. They're like subroutines in that way. This makes them inconvenient to pass around or store into data structures. Assuming you follow the prudent advice to compile all your code under `use strict` by default, normally you can't get away with this:

>     $fh = SOMEHANDLE;
>     somefunc(SOMEHANDLE);

because, absent declarations to the contrary, `SOMEHANDLE` is in both of these cases an unquoted string, which is forbidden by `use strict`. Even if you aren't using `strict subs`, you'll get into trouble if you try to pass your handle into a subroutine that was compiled under `strict refs` or in a different package than the calling code was compiled in.

The four named handles (`STDERR`, `STDIN`, `TTY`, and `ARGV`) we showed earlier didn't require special handling, but not because they are built-ins themselves; `TTY`, in fact, is not. Rather, they were okay because the built-in operations using them as arguments are all prototyped to take a filehandle argument.

So you must do one of two things. You could use a prototype for the function as explained in Recipe 7.6. Otherwise, you must use something that Perl will accept in lieu of a filehandle name. Acceptable substitutes include strings, typeglobs, references to typeglobs, and an I/O object, all of which may be stored into variables or passed into a function for later use as indirect filehandles.

>     somefunc(   SOMEHANDLE     );       # only w/ somefunc(*) proto
>     somefunc(  "SOMEHANDLE"    );       # an quoted string
>     somefunc(  *SOMEHANDLE     );       # a typeglob
>     somefunc( \*SOMEHANDLE     );       # ref to a typeglob
>     somefunc(  *SOMEHANDLE{IO} );       # an I/O object

Using a quoted string for the named handle has potential problems, as already explained, although this can work if the code is careful enough (again, see the next recipe). Better to use typeglob notation, either directly using `*SOMEHANDLE` or by reference using `\*SOMEHANDLE`:

>     somefunc(*SOMEHANDLE);
>     $fh = *SOMEHANDLE;  # or indirectly via a variable
>     somefunc($fh);

>     print $fh "data\n";

Typeglob notation spares you quoting or qualifying the handle name. It may help to conceptualize the asterisk as the type symbol for a filehandle. Like the little colored balls from high school chemistry that stood for atomic particles, it's not really true, but it is a convenient mental shorthand. By the time you understand where this model breaks down, you won't need it anymore.

If you assign any of the four alternate forms for named filehandles into a scalar variable, you can use that variable as an indirect filehandle wherever you would use a named filehandle.

However, complex expressions and subscripts into hashes or arrays cannot be used directly with built-ins like `print`, `printf`, or the line input operator. These are syntactically illegal and won't even compile:

>     @fd = (*STDIN, *STDOUT, *STDERR);
>     print $fd[1] "Type it: ";                           # WRONG
>     $got = <$fd[0]>                                     # WRONG
>     print $fd[2] "What was that: $got";                 # WRONG

With `print` and `printf`, you can get around this by using a block, returning an expression where you would place the filehandle:

>     print  { $fd[1] } "funny stuff\n";
>     printf { $fd[1] } "Pity the poor %x.\n", 3_735_928_559;
>     Pity the poor deadbeef.

That block is a proper block in all senses, so you can put more complicated code there. This sends the message out to one of two places:

>     $ok = -x "/bin/cat";
>     print { $ok ? $fd[1] : $fd[2]  } "cat stat $ok\n";
>     print { $fd[ 1 + ($ok || 0) ]  } "cat stat $ok\n";

This is so-called "indirect object" notation, discussed at length in Chapter 13. This restriction against using anything but simple scalar variables in the indirect object slot holds true for any sort of object. As with user-created objects, infix arrow notation avoids syntactic snafus here. If you have the IO::Handle module loaded, or anything that inherits from it, use an expression that produces the filehandle as though it were a proper object to invoke methods from that class:

>     $fd[1]->print("funny stuff\n");
>     ($ok ? $fd[1] : $fd[2])->print("cat stat $ok\n");

This approach of treating `print` and `printf` like object methods calls won't work for the line input operator. Assuming you've been storing typeglobs in your structure as we did previously, the built-in `readline` function reads records just as `<FH>` does. Given the preceding initialization of `@fd`, this would work:

>     $got = readline($fd[0]);

or, with IO::Handle available, you can use the `getline` method:

>     $got = $fd[0]->getline( );

IO::Handle doesn't replace the `readline` function using just one method—it uses two, one per context. If you prefer `readline`'s context-dependent behavior, you could always do this, adding something to the class on the fly:

>     sub IO::Handle::readline {
>         my $fh = shift;
>         if (wantarray) {
>             return $fh->getlines( );
>         } else {
>             return $fh->getline( );
>         }
>     }

### 7.5.4. See Also

The `open` function in perlfunc(1) and in Chapter 29 of Programming Perl; Recipe 7.1; the documentation with the standard IO::Handle module (also in Chapter 32 of Programming Perl); and the "Typeglobs and Filehandles" sections of Chapter 2 of Programming Perl

Copyright © 2003 O'Reilly & Associates. All rights reserved.