views:

2576

answers:

5

Hello,

In PHP, I can write:

$vname = 'phone';
$$vname = '555-1234';
print $phone;

... And the script will output "555-1234".

Is there any equivalent in Perl?

Edit: Thanks, CMS.

Is there any way to constrain $phone to the scope of the local block, as if I'd written "my $phone"? Using "my $$vname" gives me "Can't declare scalar dereference in my at ..." errors.

+1  A: 

You can do it in a very similar way:

$vname = "phone";
$$vname = "555-1234";
print $phone;

Edit: But that you can doesn't means that you should, the best way to manage this is as Michael says, USE HASH!

CMS
Why did I never know you could do that in Perl?
Greg Hewgill
Ta.Is there any way to constrain $phone to the scope of the local block, as if I'd written "my $phone"? Using "my $$vname" gives me "Can't declare scalar dereference in my at ..." errors.
Rob Howard
This gives me the following error: "Global symbol "$phone" requires explicit package name at temp.pl line 6."
Svante
Rob Howard - don't use "my" for $$vnameHarleqin - turn off the strict pragma, it won't work with it enabled
gpojd
If I have to turn off "strict" the construct is broken.
Svante
This is called a symbolic or soft reference, and is usually considered the wrong way to do it. Use a hash instead. :)
brian d foy
For the people downvoting this: It answered the question.
Chris Lively
Harleqin: not sure what you mean; the feature asked for exists in perl but is deemed dangerous enough to merit a strict mode specifically to prohibit it. That doesn't mean it's broken, just dangerous.
ysth
+4  A: 

You can't do this with the strict pragma enabled, and the strict pragma should usually always be enabled. You can do it with the pragma off though, take a look at this one liner:

perl -le 'my $vname = "phone"; ${ $vname } = "555-1234"; print $phone'

That will work, but this will not:

perl -Mstrict -le 'my $vname = "phone"; ${ $vname } = "555-1234"; print $phone'

"-Mstrict" tells it to "use strict".

It is almost always better to use a hash for something like this, which is about the same as an associative array in PHP.

gpojd
+40  A: 

What you're attempting to do is called a "symbolic reference." While you can do this in Perl you shouldn't. Symbolic references only work with global variables -- not lexical (my) ones. There is no way to restrict their scope. Symbolic references are dangerous. For that reason they don't work under the strict pragma.

In general, whenever you think you need symbolic references you should use a hash instead:

my %hash;
$hash{phone} = '555-1234';
print $hash{phone};

There are a few cases where symrefs are useful and even necessary. For example, Perl's export mechanism uses them. These are advanced topics. By the time you're ready for them you won't need to ask how. ;-)

Michael Carman
+10  A: 

Read Mark-Jason Dominus's rants against doing this: http://www.plover.com/perl/varvarname.html

You would limit the scope of your changes to $phone by starting the block with

local $phone;

or even

local $$vname;

(though that changes $phone for any subs called from your block too, so it's not the same as the lexical scope of a my() declaration.)

ysth
I'd never contemplated using C<local> to limit the scope of a symref. That's both interesting and perverse. It's like saying you're willing to shoot yourself in the foot but only with a BB gun.
Michael Carman
A: 

You do realize that PHP inherits many of it's features from Perl, right?

Not only can Perl do all of the symbolic reference stuff PHP can.

use strict;
use warnings;
use 5.010;

our $test=1;

# access $test through the special hash %::
say ${$::{test}}++;

# this is essentially what the previous line did.
say ${\$test}++

# same as $test
say ${test}++;

{
  # PHP's simple symbolic ref
  my $ref = "test";
  no strict 'refs';
  say $$ref++;
  say ${"test"}++;
}
{
  package d;
  say ${$main::{test}}++;

  my $ref = $main::{"test"};
  say $$ref++;

  $ref = \$main::test;
  say $$ref++;
}
Brad Gilbert