sluap has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I'm new to perl, and even newer to object orientated stuff. I am trying to write a class which allows a file handle to be accessed from more than one object method. (Hope I'm getting the terminology right here!) Here's my attempt at a module, MyFile.pm and a perl script to call it, scrap.pl I've tried to strip the code down to the essentials, I would guess the problem arises from trying to hold a filehandle reference in a hash. Can anybody suggest where I am going wrong? Thanks in advance!
## module file, MyFile.pm package MyFile; ## Constructor ## sub new { my $self = {}; bless $self; } sub open_file { my $self = shift; open(FH, "textfile") || die "can't open file"; $self->{FH} = \*FH; } sub read_file { my $self = shift; while (defined ($line = <$self->{FH}>)) { print "Line from file is: $line\n" } } 1; ## script file, scrap.pl #!/usr/local/bin/perl -w use MyFile; $my_object = MyFile->new(); $my_object->read_file();

Replies are listed 'Best First'.
RE: File handles in an object
by ferrency (Deacon) on Jul 11, 2000 at 21:21 UTC
    I got this to work:
    use strict; package MyFile; ## Constructor ## sub new { my $self = {}; bless $self; } sub open_file { my $self = shift; open(FH, "textfile") || die "can't open file"; $self->{FH} = \*FH; } sub read_file { my $self = shift; my $line; my $f = $self->{FH}; while (defined ($line = <$f>)) { print "Line from file is: $line\n"; } } my $my_object = new(); $my_object->open_file(); $my_object->read_file();
    I think what's happening is:
    <$self->{FH}>
    is being parsed like
    <$self-> {FH} >
    That is, a file handle specification, with a subscript outside the <>'s, followed by a >, which is a syntax error.

    Alan

      actually, <$self->{FH}> is a glob. btrott is right in that only a simple scalar reference can be used inside angle brackets to refer to a filehandle. anything else that's more complicated is instead a glob. these will do the same thing:
      $h{foo} = '*.c'; print <$h{foo}>
      and
      print glob $h{foo};
      and also
      print <*.c>;
Re: File handles in an object
by btrott (Parson) on Jul 11, 2000 at 21:18 UTC
    Two problems here:
    • You didn't actually call open_file in your code snippet there, so it won't work no matter what, because you haven't yet opened the file.
    • I don't think you can use complex expressions in a <> operator. You need simple expressions, so try this:
      my $fh = $self->{FH}; while (defined($line = <$fh>)) {
    Just a note: I'm assuming that you posted here because you got an error when running your code. It's helpful to actually post that error to give others some idea of the problem you're having.
RE: File handles in an object
by gnat (Beadle) on Jul 12, 2000 at 00:43 UTC
    You'll have to do two things.

    (1) As pointed out by others, <SOMETHING> is ambiguous. It's either a filehandle read or a directory glob (to get the list of files that match a pattern:

    $line = <$filehandle>; # simple scalar variable = read op @files = <*.c>; # anything else is a directory glob
    As the comments there say, the rule is: If it's a simple scalar variable, it's a filehandle. If it's a bare word it's a filehandle. Anything else and it's a directory glob.

    So you'll need to use a temporary variable:

    $tmp = $this->{THAT}->[0]->{THE_OTHER}; $line = <$tmp>;
    (2) You won't be able to successfully open more than one file (even if you hadn't hard-coded the filename :-). A common hack in Perl to get filehandles in arrays or hashes or subroutines is to use typeglobs, because Perl lets you use a scalar containing a typeglob anywhere you would normally use a filehandle. However, there's some cunning required when opening the file:

    open FH, $file1 or die; # open it, okay ... push @filehandles, *FH; # push the typeglob, fine ... open FH, $file2 or die; # reopening it, closing the previously open +ed file! push @filehandles, *FH; # push it again
    This gives you two copies of the same glob in @filehandles. What you need to do is create a new glob each time. The best way to do this is with local():

    sub open_file { my ($self, $filename) = @_; local *FH; open FH, $filename or die "opening $filename: $!"; $self->{FH} = *FH; }

    Good luck!

    Nat

(chromatic) Re: File handles in an object
by chromatic (Archbishop) on Jul 11, 2000 at 23:04 UTC
    In the absence of a bigger picture here, I'll throw out the tasty little tidbit that you can actually bless a typeglob into an object. You'll have to use the Symbol package (to get at gensym), but you can do some surprisingly nifty things with it:
    #!/usr/bin/perl -w package GlobPack; use strict; use Symbol; sub new { my $class = shift; my $file = shift || "test.txt"; $class = ref($class) || $class; my $self = gensym; open($self, $file) || return undef; return bless ($self, $class); } sub read { my $self = shift; print while (<$self>); }
    Here's some code to test this:
    package main; my $fileread = GlobPack->new('globpack.pl') || die "Can't get the glob +ject.\n"; $fileread->read();