3

I serialized my data to string in Perl using Data::Dumper. Now in another program I'm trying to deserialize it by using eval and I'm getting:

Global symbol "$VAR1" requires explicit package name

I'm using use warnings; use strict; in my program.

Here is how I'm evaling the code:

my $wiki_categories = eval($db_row->{categories});
die $@ if $@;
/* use $wiki_categories */

How can I disable my program dying because of "$VAR1" not being declared as my?

Should I append "my " before the $db_row->{categories} in the eval? Like this:

my $wiki_categories = eval("my ".$db_row->{categories});

I didn't test this yet, but I think it would work.

Any other ways to do this? Perhaps wrap it in some block, and turn off strict for that block? I haven't ever done it but I've seen it mentioned.

Any help appreciated!

bodacydo
  • 75,521
  • 93
  • 229
  • 319
  • Data::Dumper is a debugging tool. You really shouldn't use it this way. JSON is a better alternative. – ikegami Jun 21 '12 at 19:40
  • This is a follow-up to http://stackoverflow.com/questions/11092658/how-do-i-serialize-an-array-of-array-references-in-perl – daxim Jun 21 '12 at 21:42
  • You could also just say `my $VAR1; eval($db_row->{categories}); my $wiki_categories = $VAR1;` to get rid of the error. But the answers that are already there are a lot more helpful then that. Read them and try those other modules for data storage. – simbabque Jun 21 '12 at 22:34

3 Answers3

8

This is normal. By default, when Data::Dumper serializes data, it outputs something like:

$VAR1 = ...your data...

To use Data::Dumper for serialization, you need to configure it a little. Terse being the most important option to set, it turns off the $VAR thing.

use Data::Dumper;

my $data = {
    foo => 23,
    bar => [qw(1 2 3)]
};

my $dumper = Data::Dumper->new([]);
$dumper->Terse(1);

$dumper->Values([$data]);
print $dumper->Dump;

Then the result can be evaled straight into a variable.

my $data = eval $your_dump;

You can do various tricks to shrink the size of Data::Dumper, but on the whole it's fast and space efficient. The major down sides are that it's Perl only and wildly insecure. If anyone can modify your dump file, they own your program.

There are modules on CPAN which take care of this for you, and a whole lot more, such as Data::Serializer.

Schwern
  • 153,029
  • 25
  • 195
  • 336
6

Your question has a number of implications, I'll try to address as many as I can.

First, read the perldoc for Data::Dumper. Setting $Data::Dumper::Terse = 1 may suffice for your needs. There are many options here in global variables, so be sure to localise them. But this changes the producer, not the consumer, of the data. I don't know how much control you have over that. Your question implies you're working on the consumer, but makes no mention of any control over the producer. Maybe the data already exists, and you have to use it as is.

The next implication is that you're tied to Data::Dumper. Again, the data may already exist, so too bad, use it. If this is not the case, I would recommend switching to another storable format. A fairly common one nowadays is JSON. While JSON isn't part of core perl, it's pretty trivial to install. It also makes this much easier. One advantage is that the data is useful in other languages, too. Another is that you avoid eval STRING which, should the data be compromised, could easily compromise your consumer.

The next item is just how to solve it as is. If the data exists, for example. A simple solution is to just add the my as you did. This works fine. Another one is to strip the $VAR1: (my $dumped = $db_row->{categories}) =~ s/^\s*\$\w+\s*=\s*//;. Another one is to put the "no warnings" right into the eval: eval ("no warnings; no strict; " . $db_row->{categories});.

Personally, I go with JSON whenever possible.

Tanktalus
  • 21,664
  • 5
  • 41
  • 68
2

Your code would work as it stood except that the eval fails because $VAR1 is undeclared in the scope of the eval and use strict 'vars' is in effect.

Get around this by disabling strictures within as tight a block as possible. A do block does the trick, like this

my $wiki_categories = do {
  no strict 'vars';
  eval $db_row->{categories};
};
Borodin
  • 126,100
  • 9
  • 70
  • 144