11

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?

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Rob Howard
  • 1,789
  • 2
  • 20
  • 38

5 Answers5

57

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
  • 30,628
  • 10
  • 74
  • 122
13

Read Mark-Jason Dominus's rants against doing this in Why it's stupid to `use a variable as a variable name'.

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

local $phone;

or even

local $$vname;

(Though either 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
  • 96,171
  • 6
  • 121
  • 214
  • 3
    I'd never contemplated using C 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 Nov 12 '08 at 14:14
8

You can do it in a very similar way:

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

But that you can doesn't mean that you should. The best way to manage this is, as Michael Carman says, USE A HASH!

Community
  • 1
  • 1
Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
  • 1
    Why did I never know you could do that in Perl? – Greg Hewgill Nov 12 '08 at 01:01
  • 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 Nov 12 '08 at 01:07
  • This gives me the following error: "Global symbol "$phone" requires explicit package name at temp.pl line 6." – Svante Nov 12 '08 at 01:11
  • Rob Howard - don't use "my" for $$vname Harleqin - turn off the strict pragma, it won't work with it enabled – gpojd Nov 12 '08 at 01:14
  • 8
    If I have to turn off "strict" the construct is broken. – Svante Nov 12 '08 at 01:58
  • 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 Nov 12 '08 at 02:43
  • 1
    For the people downvoting this: It answered the question. – NotMe Nov 13 '08 at 02:15
  • 1
    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 Nov 13 '08 at 06:24
6

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
  • 22,558
  • 8
  • 42
  • 71
0

You do realize that PHP inherits many of its 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++;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Brad Gilbert
  • 33,846
  • 11
  • 78
  • 129