Tied filehandles#

A tied filehandle reroutes I/O the way a tied scalar reroutes reads and writes. Print to it and your PRINT runs; read a line and your READLINE runs. The classic uses are redirecting output somewhere unusual (into a string, across a network, through a filter) and embedding Perl in a host program that needs STDOUT and STDERR handled specially.

The interface is larger than the others but mostly optional: you implement only the operations the handle will actually receive. The full menu is on the tie reference page; this chapter builds a class and explains the hooks and their timing.

A complete class#

A write-only handle that collects everything printed to it into a string:

use v5.36;

package Collector {
    sub TIEHANDLE { my $class = shift; my $buf = ''; return bless \$buf, $class }
    sub PRINT     { my $self = shift; $$self .= join($, // '', @_); return 1 }
    sub PRINTF    { my $self = shift; my $fmt = shift; $$self .= sprintf($fmt, @_); return 1 }
    sub buffer    { my $self = shift; return $$self }
}

tie *OUT, 'Collector';
print OUT "hello ";
print OUT "world\n";
printf OUT "%d items\n", 3;
my $obj = tied *OUT;
print $obj->buffer;
# hello world
# 3 items

The object is a blessed scalar ref holding the accumulated text. The extra buffer method is reached through tied, not through any I/O operation - that is the standard way a tie class exposes operations with no filehandle syntax.

Tying the glob, not the scalar#

The first argument to tie for a handle must be a glob - it begins with an asterisk:

  • To tie a named handle: tie *OUT, 'Collector'.

  • To tie a handle held in a scalar $fh: tie *$fh, 'Collector'. Writing tie $fh, ... ties the scalar $fh, not the handle inside it - a common and confusing mistake.

The method contract#

TIEHANDLE classname, LIST

The constructor; returns a blessed reference of any kind. It can hold whatever internal state the handle needs.

PRINT this, LIST

Backs print and say. It receives the printed list. Honour $, (the output field separator) between items and $\ (the output record terminator) at the end if you want full fidelity - print does not insert them for you.

PRINTF this, format, LIST

Backs printf. It receives the format string and arguments; run them through sprintf yourself.

WRITE this, scalar, length, offset

Backs syswrite - the raw, buffer-oriented write, distinct from PRINT.

READLINE this

Backs <$fh> and readline. In scalar context return the next line or undef at end of input; in list context return all remaining lines or an empty list. The returned strings should include the input record separator $/, matching what a real handle gives you.

READ this, scalar, length, offset / GETC this

Back read / sysread and getc respectively.

OPEN, CLOSE, EOF, BINMODE, FILENO, SEEK, TELL

Back the corresponding built-ins when used on the handle. Implement the ones that make sense for your backing store and leave the rest out.

DESTROY this / UNTIE this

Optional cleanup, identical in role to the other tie types. A handle class often closes its backing resource here.

Call timing#

  • print FH @list and say FH @listPRINT. say additionally localises $\ to "\n" around the call, so a PRINT that honours $\ handles say with no special case.

  • printf FH $fmt, @argsPRINTF.

  • syswrite FH, $buf, $len, $offWRITE.

  • <FH> / readline FHREADLINE, in the surrounding context.

  • read/sysreadREAD; getc FHGETC.

  • close FH, eof FH, binmode FH, seek, tell, fileno, open FH, ... → the matching uppercase hook when defined.

A note on STDERR: when STDERR is tied, its PRINT is what issues warnings and error messages. The runtime disables the tie for the duration of that call, so you can warn from inside PRINT without triggering infinite recursion.

Minimum viable class#

There is no single mandatory method beyond TIEHANDLE - you implement whichever operations the handle will receive. An output-only handle needs TIEHANDLE plus PRINT (and usually PRINTF). An input-only handle needs TIEHANDLE plus READLINE (and perhaps GETC / READ). Operations whose hook is missing die at the point of use, so define exactly the set your callers exercise.

The easy way: inherit from Tie::StdHandle#

Tie::StdHandle (shipped inside Tie::Handle) ties a handle onto a real underlying one: its OPEN opens an actual file and the I/O hooks forward to it. Inherit from it and override only the operations you want to intercept:

package Doubler {
    use Tie::StdHandle;
    our @ISA = ('Tie::StdHandle');
    sub READLINE {
        my $self = shift;
        my $line = $self->SUPER::READLINE;
        return defined $line ? $line . $line : undef;   # echo each line twice
    }
}

my $data = "a\nb\n";
tie *DUP, 'Doubler';
tied(*DUP)->OPEN('<', \$data);
print while defined($_ = <DUP>);
# a
# a
# b
# b

READLINE calls up to the base class for the real next line, then doubles it; every other operation flows through Tie::StdHandle unchanged. Tie::Handle (the parent) is the abstract base that documents the interface and supplies a default PRINT/PRINTF in terms of WRITE; Tie::StdHandle is the concrete, ready-to-use one.

See also#

  • tie - the built-in and the full handle method menu

  • tied - the only way to reach a handle class’s non-I/O methods, like buffer above

  • print and printf - the built-ins behind PRINT and PRINTF

  • readline - its page documents the scalar/list return contract READLINE must honour

  • Tied scalars - the simplest tie type, a good warm-up for the handle interface

  • Tie::Handle - the base-class module; Tie::StdHandle is the concrete version