in reply to Grabbing Variable Names
A typeglob's variable data can also be reached through subscribing it with the type of data you want (called the *foo{THING} syntax): SCALAR, ARRAY, HASH, CODE, IO, GLOB, (FILEHANDLE). E.g. *foo{ARRAY} gives a reference to @foo. Something to be aware of is that SCALAR always returns a reference. If the scalar slot for that typeglob isn't defined an anonymous scalar reference will be returned instead. This means that you cannot do if (*foo{SCALAR}) instead of if (defined $$foo) because the former will always be true. Also, for subroutines there is a difference between definedness and typeglob slot existance. A forward-declared subroutine will have *foo{CODE} return true, but if it isn't defined with a body later on (sub foo { ... }) defined &foo will return false. (You can also check if a subroutine has been declared (independently of defined) with exists &foo). It's up to you how you choose to handle this. A forward declaration might indicate that the subroutine will be generated or handled by an AUTOLOAD routine, so you could claim that it exists, when needed.# We define this subroutine anonymously and store it in a lexical # scalar to avoid it getting found by itself. my $find_globs; $find_globs = sub { my ($pkg) = @_; my @vars; no strict 'refs'; my @globs = values %$pkg; # The symbol table is made available through a hash. That hash is # the package's name plus two colons. The values in the symbol # table are typeglobs. Typeglobs are holders of the values used # when you access a global variable, like $foo. That accesses # the *foo typeglob's scalar value. Typeglobs are prefixed with # a "*", as you can see. foreach my $glob (values %$pkg) { my $name = *$glob{NAME}; # Each glob also saves its name, next to the variable-data. if ($name =~ /::\z/) { # As you might recall, a symbol table is made available # through a hash which ends in "::". This hash also lives in # a typeglob, and is thus stored in the symbol table. # (Actually, I'm kind of cheating here. There could be # other datatypes defined here than the hash, and perhaps # the hash isn't even defined. The program won't break # if there are; it just won't return non-hashes that end # with "::".) push @vars => $find_globs->("$pkg$name") unless $name eq 'main::'; # From the main package all packages can be reached, even # main itself. That means *main::main:: points to main. You # see where this is leading us: nowhere. So don't follow # any mains. } else { my @types = ( defined $$glob ? '$' : (), defined @$glob ? '@' : (), defined %$glob ? '%' : (), defined &$glob ? '&' : (), ); # Here we see which data types are defined. push @vars => map $_ . *$glob{PACKAGE} . "::$name", @types; # Not only does it save the name, it also saves the package # it lives in. } } return @vars; }; use Data::Dumper; # Just to get extra packages. :) # Here you might want to do() your program file. print "$_\n" for $find_globs->('main::');
|
---|
Replies are listed 'Best First'. | |
---|---|
Re^2: Grabbing Variable Names
by mab (Acolyte) on Mar 30, 2005 at 19:17 UTC | |
by ihb (Deacon) on Mar 30, 2005 at 21:19 UTC |