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'. Writingtie $fh, ...ties the scalar$fh, not the handle inside it - a common and confusing mistake.
The method contract#
TIEHANDLE classname, LISTThe constructor; returns a blessed reference of any kind. It can hold whatever internal state the handle needs.
PRINT this, LISTBacks
printandsay. 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 -printdoes not insert them for you.PRINTF this, format, LISTBacks
printf. It receives the format string and arguments; run them throughsprintfyourself.WRITE this, scalar, length, offsetBacks
syswrite- the raw, buffer-oriented write, distinct fromPRINT.READLINE thisBacks
<$fh>andreadline. In scalar context return the next line orundefat 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 thisOPEN,CLOSE,EOF,BINMODE,FILENO,SEEK,TELLBack 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 thisOptional cleanup, identical in role to the other tie types. A handle class often closes its backing resource here.
Call timing#
print FH @listandsay FH @list→PRINT.sayadditionally localises$\to"\n"around the call, so aPRINTthat honours$\handlessaywith no special case.printf FH $fmt, @args→PRINTF.syswrite FH, $buf, $len, $off→WRITE.<FH>/readline FH→READLINE, in the surrounding context.read/sysread→READ;getc FH→GETC.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 menutied- the only way to reach a handle class’s non-I/O methods, likebufferabovereadline- its page documents the scalar/list return contractREADLINEmust honourTied scalars - the simplest tie type, a good warm-up for the handle interface
Tie::Handle- the base-class module;Tie::StdHandleis the concrete version