13

I am trying to get a text representation of a variable's name. For instance, this would be the function I am looking for:

$abc = '123';
$var_name = &get_var_name($abc); #returns '$abc'

I want this because I am trying to write a debug function that recursively outputs the contents of a passed variable. I want it to output the variable's name before hand so if I call this debug function 100 times in succession, there will be no confusion as to which variable I am looking at in the output.

I have heard of Data::Dumper and am not a fan. If someone can tell me how to if it's possible get a string of a variable's name, that would be great.

toolic
  • 57,801
  • 17
  • 75
  • 117
Jose Cuervo
  • 131
  • 1
  • 3
  • 4
    Why not just use Perl's built-in debugging tools instead of reinventing the wheel? – Cfreak Mar 04 '11 at 22:17
  • 1
    I suspect that Devel::StackTrace would be a better solution to your problem then hunting down variable names. – Quentin Mar 04 '11 at 22:18
  • 1
    Why aren't you a fan of Data::Dumper? If we know exactly what your requirements are and why Data::Dumper doesn't satisfy them, it will be easier to answer your question. Without further information, all I can do is recommend Data::Dumper because it's what I use for this. – Philip Potter Mar 04 '11 at 22:19
  • 2
    I don't actually see what help Data::Dumper would be in this case. – JB. Mar 04 '11 at 22:28

3 Answers3

13

Data::Dumper::Simple

use warnings;
use strict;
use Data::Dumper::Simple;

my $abc = '123';
my ($var_name) = split /=/, Dumper($abc);
print $var_name, "\n";

__END__

$abc
toolic
  • 57,801
  • 17
  • 75
  • 117
9

To do this, you need to use the module PadWalker, which lets you inspect the lexical pads that store variables.

use PadWalker qw/peek_my peek_our/;

sub debug {
    my $my     = peek_my 1;
    my $our    = peek_our 1;
    my $caller = caller() . '::';
    my $stash  = do {
        no strict 'refs';
        \%$caller
    };
    my %lookup;
    for my $pad ($my, $our) {
        $lookup{$$pad{$_}} ||= $_ for keys %$pad;
    }
    for my $name (keys %$stash) {
        if (ref \$$stash{$name} eq 'GLOB') {
            for (['$' => 'SCALAR'],
                 ['@' => 'ARRAY'],
                 ['%' => 'HASH'],
                 ['&' => 'CODE']) {
                if (my $ref = *{$$stash{$name}}{$$_[1]}) {
                    $lookup{$ref} ||= $$_[0] . $caller . $name
                }
            }
        }
    }
    for (@_) {
       my $name = $lookup{\$_} || 'name not found';
       print "$name: $_\n";
    }
}

and then to use it:

my $x = 5;
our $y = 10;
$main::z = 15;

debug $x, $y, $main::z;

which prints:

$x: 5
$y: 10
$main::z: 15

EDIT:

Here is the same functionality, refactored a bit:

use PadWalker qw/peek_my peek_our/;

sub get_name_my {
    my $pad = peek_my($_[0] + 1);
    for (keys %$pad) {
        return $_ if $$pad{$_} == \$_[1]
    }
}
sub get_name_our {
    my $pad = peek_our($_[0] + 1);
    for (keys %$pad) {
        return $_ if $$pad{$_} == \$_[1]
    }
}
sub get_name_stash {
    my $caller = caller($_[0]) . '::';
    my $stash = do {
        no strict 'refs';
        \%$caller
    };
    my %lookup;
    for my $name (keys %$stash) {
        if (ref \$$stash{$name} eq 'GLOB') {
            for (['$' => 'SCALAR'],
                 ['@' => 'ARRAY'],
                 ['%' => 'HASH'],
                 ['&' => 'CODE']) {
                if (my $ref = *{$$stash{$name}}{$$_[1]}) {
                    $lookup{$ref} ||= $$_[0] . $caller . $name
                }
            }
        }
    }
    $lookup{\$_[1]}
}
sub get_name {
    unshift @_, @_ == 2 ? 1 + shift : 1;
    &get_name_my  or
    &get_name_our or
    &get_name_stash
}

sub debug {
    for (@_) {
       my $name = get_name(1, $_) || 'name not found';
       print "$name: $_\n";
    }
}
Eric Strom
  • 39,821
  • 2
  • 80
  • 152
-4

"my" (lexical) variables' names are erased, so you can't get their names. Package variables' names are available via the symbol table entry (*var), as mentioned elsearticle.

geekosaur
  • 59,309
  • 11
  • 123
  • 114
  • That was definitely not the question. And there IS a way to get names of lexical and global variables used in a call. Look at the other answers. Look at Devel::Caller and PadWalker. – Francisco Zarabozo Aug 22 '20 at 05:19