heezy has asked for the wisdom of the Perl Monks concerning the following question:
Hi all!
Is it possible to use strings joined together to reference a variable? Let me demonstrate what I would like to do...
$wonderFull = "The String I want to get at";
$var1 = "wonder"
$var2 = "Full"
$temp = $var1 . $var2
Now obviously that wont work as "." just joins things. I want temp to be set to the value of $wonderFull.
Is this even possible?
Thanks people,
M
The reason I want to do this is that I will have a large cgi script with many predefined open file handles. I want the user to select two values from pull down boxes on a web page and then by using these it will use the correct file handle. It could be done with lots of if statements but there must be a better way to do it?
Re: Many strings make one variable?
by Abigail-II (Bishop) on Oct 14, 2002 at 17:48 UTC
|
If $wonderFull is a package variable, you could
do:
{
no strict 'refs';
$temp = ${$var1 . $var2};
}
But you don't really want to do that.
The reason I want to do this is that I will have a large cgi script with many predefined open file handles. I want the
user to select two values from pull down boxes on a web page and then by using these it will use the correct file
handle. It could be done with lots of if statements but there must be a better way to do it?
If that is what you want, why didn't you just ask that? Now your
question is of the form "How do I do X, because I want to do Y, and
I might be able to do that with X". Better is to ask "How do I do Y?",
because the answer is Z. And Z is "Use a hash". In your case, a 2 dimensional
hash. The selected values will be the entries, and the filehandles
(or rather, references to them), the values.
Abigail | [reply] [d/l] [select] |
|
| [reply] |
Re: Many strings make one variable?
by sauoq (Abbot) on Oct 14, 2002 at 17:51 UTC
|
Yes, it is possible but it is very rarely a good idea. Here's how to do it:
$temp = ${$var1 . $var2};
In your case, it would probably be better to use a hash or maybe even a hash of hashes. Doing it the way you are trying to could be downright dangerous in a CGI environment. You should be using -T to turn on tainting and remind you to carefully validate user input. (I'm assuming you mean file names rather than file handles because it is unlikely that you would need to have a bunch of file handles available if the user is only choosing one.)
-sauoq
"My two cents aren't worth a dime.";
| [reply] [d/l] |
Re: Many strings make one variable?
by fruiture (Curate) on Oct 14, 2002 at 17:56 UTC
|
What you're trying to do can be achieved with symbolic references, but that's _bad_. The need for symrefs is an indicator for spaghetti code. Use a hash instead:
my %symbols = (
'wonderFull' => 'The String I want to get at'
);
my ($var1,$var2) = qw/wonder Full/
print $symbols{ $var1 . $var2 }
You must never mix two layers of your program: the data that is in the variables and the names of variables. Keep them seperate, they _are_ seperate. The possibility to mix these two is for "advanced, internal stuff" and must not be used in CGI scripts, for that's a big security risk.
--
http://fruiture.de | [reply] [d/l] |
Re: Many strings make one variable?
by antifun (Sexton) on Oct 14, 2002 at 18:26 UTC
|
no strict 'refs';
$value = ${$foo . $bar}
is fine and useful for one-off scripts. It might even be acceptable in a standalone application, if you are careful about what $foo and $bar are.
However, it is almost certainly begging for disaster in a CGI script unless you carefully validate your input, and the code you spend doing that would probably end up being longer than the code necessary to do it a better way (with a hash, as suggested above, for one).
---
"I hate it when I think myself into a corner."
Matt Mitchell | [reply] [d/l] |
Re: Many strings make one variable?
by Anonymous Monk on Oct 14, 2002 at 18:39 UTC
|
#!perl
use strict;
# You *must* use "our" instead of "my" here
# or, you can omit the 'use strict;' above and avoid
# the 'my/our' issue altogether.
our $wonderFull = "The String I want to get at\n";
my $var1 = "wonder";
my $var2 = "Full";
my $temp;
{
# use some symbolic variable references within this scope
no strict qw/refs/;
# dereference "wonderFull" and copy the contents to $temp
$temp = ${ $var1 . $var2 };
print $temp;
# make the variable name so we can assign to the symbolic variable
$temp = $var1 . $var2;
# now assign to $wonderFull
$$temp = "new string\n";
}
# note that the contents of $wonderFull have changed
print $wonderFull;
edited: Tue Oct 15 17:35:48 2002
by jeffa - code tags s/<BR>//g
| [reply] [d/l] [select] |
Re: Many strings make one variable?
by true (Pilgrim) on Oct 14, 2002 at 18:59 UTC
|
I do this all the time and have been waiting for the right guru to smack me down for doing it this way. The only pitfall to watch out for is if the first character in your dynamic variable has to be in a letter range a-zA-Z.
So
$wonderful = "A good Thing to behold";
$var1 = "wonder";
$var2 = "full";
$iz = $var1.$var2;
$perlmonks = $$iz;
In this sample $perlmonks is equal to
"A good Thing to Behold";
Also if $var1 = "1sometthing";
Your script will crash.
A note to the guru who will smack me down. Please don't tell me this is a bad idea without saying why.
tanx.
|
| [reply] [d/l] |
|
I'm no guru, but I'll give you some reasons why not. Here's three off the top of my head:
- Soft references are global
- What if $var1 == 'con' and $var2 == 'fig' - and $config is a very important variable?
- What if a later programmer (like you?) wanted to add a variable named $config later? He would have to check to make sure that 'config' was not a valid value of $var1.$var2
Don't just listen to me (or sauoq or fruiture or Abigail-II above), go to http://perl.plover.com and read what dominus thinks of using a variable as a variable name - Part
1, 2, and 3
| [reply] [d/l] [select] |
|
I keep all my import variables in a hash for safe keeping.
I let these dynamic variables as listed above exist in the main root hash environment (if you could call it that).
so there's %ENV, %GET, %POST, %IP, %DEFAULTS, and %DATABASE.
This is safer anyway. measure twice, declare once.
I'm still not saying i'm right, but anti-soft reference arguments don't float.
Maybe it's the hash.
I wonder if a reminder of the beauty of 'local' would also help the case here.
After reading dominus's arguments against soft references i still remain. One could spend hours telling you how dangerous using perl is when you use the shebang line.
Then, i thought of 'local' and did a test...
Error 500 in the face.
This doesn't work.
#!/usr/bin/perl
&tryLocal("name=james&color=red&age=12");
exit;
####################
sub tryLocal{
local $in = $_[0];
@in = split(/\&/,$in);
foreach $li(@in){
($lname,$lvalue)=split(/\=/,$li);
local $$lname = $lvalue;
}
}################# end tryLocal
This works.
#!/usr/bin/perl
&tryLocal("name=james&color=red&age=12");
exit;
####################
sub tryLocal{
local $in = $_[0];
@in = split(/\&/,$in);
foreach $li(@in){
($lname,$lvalue)=split(/\=/,$li);
$$lname = $lvalue;
}
}################# end tryLocal
Which leads me to say. I was wrong.
As you fall in love with local
(which i have been doing all summer),
you must abandon my old ways.
Create your hash and check $TEMP{$passcode}
instead of $passcode.
|
| [reply] [d/l] [select] |
|
|
|
|
|
|
|
| [reply] [d/l] [select] |
|
|