The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

Name

Tie::Handle::Base - A base class for tied filehandles

Synopsis

 package Tie::Handle::Mine;
 use parent 'Tie::Handle::Base';
 sub WRITE {
     my $self = shift;
     print STDERR "Debug: Output '$_[0]'\n";
     return $self->SUPER::WRITE(@_);
 }

Then use your custom tied handle:

 open my $fh, '>', $filename or die $!;
 $fh = Tie::Handle::Mine->new($fh);  # replace orig. handle with tied
 print $fh "Hello, World";           # debug message will be printed
 close $fh;

Description

Tie::Handle::Base is a base class for tied filehandles. It is similar to Tie::StdHandle, but provides a few more features, and is compatible down to Perl 5.8.1. It tries to be as transparent as possible (one limitation is that sysread and syswrite are only emulated, as described in "READ").

A few limitations that exist in Tie::StdHandle (at least versions up to and including 4.4) have been lifted: BINMODE accepts the LAYER argument, and WRITE will return the length of the string written.

This documentation describes version 0.08 of this module.

See Also: perltie, "tie" in perlfunc, Tie::Handle, Tie::StdHandle

Examples

Debugging

This is a slightly "fancier" version of the example presented in the "Synopsis", this prints all calls on the tied handle using Class::Method::Modifiers's before and Data::Dump.

 package Tie::Handle::Debug;
 use parent 'Tie::Handle::Base';
 use Class::Method::Modifiers 'before';
 use Data::Dump 'dd';
 for my $method (@Tie::Handle::Base::ALL_METHODS) {
     before $method => sub { dd $method, @_[1..$#_] };
 }

Tee

Here is a simple "tee" implementation - anything written to the tied handle via print, printf, and syswrite will end up being written to all handles given to new (the first handle being the "main" handle that all the other I/O functions in this example, including close, are performed on).

 package Tie::Handle::Tee;
 use parent 'Tie::Handle::Base';
 sub TIEHANDLE {
     my ($class,$main,@others) = @_;
     my $self = $class->SUPER::TIEHANDLE($main);
     $self->{others} = \@others;
     return $self;
 }
 sub WRITE {
     my $self = shift;
     $self->inner_write($_, @_) for @{$self->{others}};
     return $self->SUPER::WRITE(@_);
 }

Note that you may wrap one tied handle in another - for example, my $fh = Tie::Handle::Debug->new( Tie::Handle::Tee->new(@handles) ).

Methods

This section documents the methods of this class. Those methods that wrap/emulate Perl's functionality also attempt to emulate the return values of the original Perl functions.

new

new will create a new lexical filehandle, tie it to the class (thus invoking "TIEHANDLE"), and return that filehandle. Any arguments to new are passed through to TIEHANDLE, including the (optional) inner handle as the first argument.

It is recommended for subclasses to override TIEHANDLE instead of new, as this will provide a more consistent interface for users wishing to use Perl's tie instead of new.

TIEHANDLE

This method takes a single optional argument, which is the inner handle which is wrapped by the tied handle. If this inner handle is not given, the method will create a new lexical filehandle that is otherwise uninitialized. The method then creates a new hashref which will serve as the object of the specified class, and which implements the tied interface based on this class. This object is also what is returned by tied(*$handle).

Subclasses may store whatever they like in this hashref, except that keys beginning with two underscores (__) are reserved for this base class. Subclasses overriding this method should still call it via the usual $class->SUPER::TIEHANDLE(...).

UNTIE and DESTROY

These methods discard the inner handle which this class wraps. Subclasses overriding these methods should call the superclass methods.

innerhandle

This method returns the inner handle which is wrapped by this class.

Subclasses wishing to change the inner handle may do so with the set_inner_handle method, which takes a single argument, the new inner handle.

OPEN

This implementation will first call the FILENO method and check for definedness to see if the inner handle is still open, and if it is, call the CLOSE method before calling Perl's open to open the inner handle.

PRINT, PRINTF, and WRITE

The methods PRINT and PRINTF emulate the Perl functions by the same name by building the output strings and passing them to the WRITE method. This means that subclasses can modify output behavior by overriding only the WRITE method. WRITE itself is simply a call to "inner_write".

inner_write

This function, intended for use by subclasses, may be called as either a simple function, or as a method on the object, so that subclasses may call $self->inner_write($handle, ...). In either case, the argument list must be the same as that of syswrite, including the filehandle which to output on as the first argument. This function emulates syswrite behavior using substr and Perl's print. It does not use syswrite internally in order to be analogous to the "READ" implementation.

READ

Perl's tied filehandle interface will call this method for both read and sysread calls. This method calls Perl's read, not sysread, because the latter would bypass buffered I/O and cause confusion with other buffered I/O methods such as seek, tell, and eof.

This means that one limitation of this base class is that, while users may call sysread and syswrite on the tied handles, these calls will not be translated into sysread/write calls on the inner, wrapped handle. (See "inner_write" regarding syswrite.)

All Other Methods

The methods BINMODE, CLOSE, EOF, FILENO, GETC, READLINE, SEEK, and TELL are implemented in this class by calling the Perl functions of the same name.

The full list of methods that tied handles can/should implement is as follows. The list of names is provided as @Tie::Handle::Base::ALL_METHODS, and the list @Tie::Handle::Base::IO_METHODS excludes TIEHANDLE, UNTIE, and DESTROY.

 -- Method of the "tie" Interface ------------+-- Perl Prototype* ----
  BINMODE this                                | binmode   (*;$)      
  CLOSE this                                  | close     (;*)       
  EOF this                                    | eof       (;*)       
  FILENO this                                 | fileno    (*)        
  GETC this                                   | getc      (;*)       
  OPEN this, filename / OPEN this, mode, LIST | open      (*;$@)     
  PRINT this, LIST                            | print     none*      
  PRINTF this, format, LIST                   | printf    none*      
  READ this, scalar, length, offset           | (sys)read (*\$$;$)   
  READLINE this                               | readline  (;*)       
  SEEK this, offset, whence                   | seek      (*$$)      
  TELL this                                   | tell      (;*)       
  WRITE this, scalar, length, offset          | syswrite  (*$;$$)    
  TIEHANDLE classname, LIST                   | tie       (\[$@%*]$@)
  UNTIE this                                  | untie     (\[$@%*])  
  DESTROY this                                | N/A

* Prototypes as reported by the prototype function as of Perl 5.26. Note that print and printf get special handling by Perl and therefore do not report a standard prototype.

Author, Copyright, and License

Copyright (c) 2017 Hauke Daempfling (haukex@zero-g.net) at the Leibniz Institute of Freshwater Ecology and Inland Fisheries (IGB), Berlin, Germany, http://www.igb-berlin.de/

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.