Get variable name as string in Perl

后端 未结 3 1081
一个人的身影
一个人的身影 2021-01-04 10:31

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 = &         


        
相关标签:
3条回答
  • 2021-01-04 11:20

    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";
        }
    }
    
    0 讨论(0)
  • 2021-01-04 11:22

    "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.

    0 讨论(0)
  • 2021-01-04 11:26

    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
    
    0 讨论(0)
提交回复
热议问题