Hack #75. Find All Symbols in a Package
Explore symbol tables without soft references.
One of the earliest temptations
for novice programmers is to use the contents of one variable as part of the name of another variable. After making one too many costly mistakes or showing such code to a more experienced programmer, novices start to use the strict pragma to warn them about dubious constructs.
However, several advanced features of Perl, such as the implementation of the Exporter module, are only possible by reading from and writing to the symbol table at run time. Normally strict forbids this—but it's possible to access global symbols at run time with strict enabled.
This is an easy way to find out if a symbol—such as a scalar, array, hash, subroutine, or filehandle—exists.
The Hack
Suppose you want to check whether a specific type of variable is present in a given namespace. You need to know the name of the package, the name of the variable, and the type of the variable.
Defining the following subroutine in the UNIVERSAL package makes the class method contains_symbol available to any package:[4]
my %types = ( '$' => 'SCALAR', '@' => 'ARRAY', '%' => 'HASH', '*' => 'IO', '&' => 'CODE', ); sub UNIVERSAL::contains_symbol { my ($namespace, $symbol) = @_; my @keys = split( /::/, $namespace ); my $type = $types{ substr( $symbol, 0, 1, '' ) } || 'SCALAR'; my $table = \\%main::; for my $key (@keys) { $key .= '::'; return 0 unless exists $table->{$key}; $table = $table->{$key}; } return 0 unless ...