The thing to remember is that the package global symbol table is pretty much a fancy special hash itself. In many cases, what can be done in global namespace, can be done in lexical namespace with a lexically scoped hash. Consider the following code:
$t = 1;
${ "type" . $t } = "Hello world!\n";
print $type1;
print ${$main::{type1}}
__OUTPUT__
Hello world!
Hello world!
Ok, so what you've done here is use a "soft reference" to create an entry in the package global symbol hash. The first 'print' shows that the new entry functions just like a regular variable. The second 'print' shows that it is also just the scalar associated with the typeglob held in %main:: You have created, in other words, a hash element whos key is 'type1' in the global hash.
Next, consider the following code:
$t = 1;
$hash{"type" . $t } = "Hello world!\n";
print $hash{type1};
print ${$main::{hash}}{type1};
__OUTPUT__
Hello world!
Hello world!
Now you've created a hash that has a key named 'type1' in a hash named %hash. There's nothing new about the first 'print'... and the second 'print' just dereferences the global symbol table to get at the element named 'hash', and further treats that element as a reference to a hash with a key named 'type1'. In so many cases, if you think you need something like my first example, you can probably get along just fine with something like my second example, without giving your code access to the symbol table.
So using a hash instead of a symbolic ref, in many cases can be used instead of the symbolic ref in the first place. All you've really done anyway is create a hash entry either way.
Now for the lexical part... you can further modify the second example as follows:
my $t = 1;
my %hash;
$hash{"type" . $t } = "Hello world!\n";
print $hash{type1};
print ${$main::{hash}}{type1};
__OUTPUT__
Hello world!
Now you've made your hash lexical, so it doesn't get an entry in the global symbol table, so the second 'print' doesn't print anything. What does this accomplish? Among other things, it reduces global namespace polution. It also reigns in the potential for all sorts of difficult to extinguish headaches, by allowing your code to run properly under use strict; (Without strictures, it's hard to detect misspelled variable names in code, for example.)
Now for another reason of why this is desirable...
In your case you're working with CGI. Though your particular code doesn't appear to be at risk of namespace contamination through malicious injections, once you start down the symbolic ref road, you really have to be careful. How easy it would be for you to inadvertantly create an entry in the global symbol table via a symbolic ref that happened to at some point originate via user input, or external file input. And when that happens, you have the potential for trouble.
So again, feel free to play with matches if your intention and need is to have a flame. But if all you need is a little light, consider a lightbulb -- it's safer.
Update: Thanks ysth for helping me with a couple edit suggestions that improved this node's readability and verbal accuracy.
|