Question

I want to do the same thing as

open MYFILE, ">", "data.txt";
print MYFILE "Bob\n";

but instead in class variable like

sub _init_tmp_db
{
    my ($self) = @_;

    open $$self{tmp_db_fh}, ">", "data.txt";
    print $$self{tmp_db_fh} "Bob\n";
}

It gave me this error : 'String found where operator expected near "Bob\n"'

what should I do?

Was it helpful?

Solution

From the print manpage:

If you're storing handles in an array or hash, or in general whenever you're using any expression more complex than a bareword handle or a plain, unsubscripted scalar variable to retrieve it, you will have to use a block returning the filehandle value instead.

You should be using:

print { $$self{tmp_db_fh} } "Bob\n";

This code won't work under use strict. To fix it just use a my variable:

open my $fh, ">", "data.txt" or die $!;
$$self{tmp_db_fh} = $fh;
print { $$self{tmp_db_fh} } "Bob\n";

OTHER TIPS

You should the IO::File module instead.

use IO::File;
my $file = IO::File->new;
$file->open("> data.txt");

print_something($file);

sub print_something {
  my ($file) = @_;
  $file->print("hello world\n");
} 

Or in your example function:

use IO::File;
# ...
sub _init_tmp_db
{
    my ($self) = @_;

    $self{tmp_db_fh} = IO::File->new;
    $self{tmp_db_fh}->open(">", "data.txt");
    $self{tmp_db_fh}->print"Bob\n";
}

(note, you can still non -> based calls too, but I wrote the above using the more traditional ->open() type calls.)

Filehandles can only be scalars.

But $$self{tmp_db_fh} is either an open filehandle (to data.txt) then this would work:

sub _init_tmp_db
{
  my ($self) = @_;

  my $filehandle = $$self{tmp_db_fh} ;
  print $filehandle "Bob\n";
}

or you open the filehandle inside _init_tmp_db

sub _init_tmp_db
{
  my ($self) = @_;

  open my $filehandle , ">", "data.txt" or die "Cannot open data.txt" ;
  print $filehandle "Bob\n";
}

But providing a string in $$self{tmp_db_fh} (like 'FILEHANDLE') won't work.

This is easily solved by creating a variable for a file handle:

sub _init_tmp_db {
    my $self = shift;

    my $fh;
    open $fh, ">", "data.txt"
    $self->{temp_db_fh} = $fh;

    # Sometime later...

    $fh = $self-{temp_db_hf};
    print $fh "Bob\n";
}

This is an issue because the way the print syntax is parsed and the early sloppiness of the syntax. The print statement has really two separate formats: Format #1 is that the you're simply passing it stuff to print. Format #2 says that the first item may be a file handle, and the rest is the stuff you want to print to the file handle. If print can't easily determine that the first parameter is a file handle, it fails.

If you look at other languages, they'll use a parameter for passing the file handle, and maybe the stuff to print. Or in object oriented languages, they'll overload >> for the file handle parameter. They'll look something like this:

print "This is my statement", file=file_handle;

or

print "This is my statement" >> file_handle;

You might be able to munge the syntax to get away from using a variable. However, it doesn't make the program more efficient or more readable, and may simply make the program harder to maintain. So, just use a variable for the file handle.


You said class in your title. I assume that you are interested in writing a fully fledge object oriented package to do this. Here's a quick example. Notice in the write subroutine method I retrieve the file handle into a variable and use the variable in the print statement.

#! /usr/bin/env perl
#
use strict;
use warnings;


#######################################################
# MAIN PROGRAM
#
my $file = File->new;

$file->open("OUTPUT") or
    die "Can't open 'OUTPUT' for writing\n";

$file->write("This is a test");
#
#######################################################

package File;
use Carp;


sub new {
    my $class = shift;

    my $self = {};
    bless $self, $class;

    return $self;
}

sub open {
    my $self = shift;
    my $file = shift;

    my $fh;
    if (defined $file) {
        $self->{FILE} = $file;
        open ($fh, ">", $file) and $self->_fh($fh);
    }
    return $self->_fh;
}

sub _fh {
    my $self = shift;
    my $fh   = shift;

    if (defined $fh) {
        $self->{FH} = $fh;
    }
    return $self->{FH};
}

sub write {
    my $self = shift;
    my $note = shift;

    my $fh = $self->_fh;
    print $fh $note . "\n";
    return
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top