Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

Many strings make one variable?

by heezy (Monk)
on Oct 14, 2002 at 17:42 UTC ( [id://205160]=perlquestion: print w/replies, xml ) Need Help??

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?

Replies are listed 'Best First'.
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

      Thanks to everyone who replied on this issue, you were all a great help!

      M

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.";
    
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
Re: Many strings make one variable?
by antifun (Sexton) on Oct 14, 2002 at 18:26 UTC

    Two more cents worth:

    Playing around with "manufactured" references like

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

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

        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.
      Well, I dont really count as a Guru. But I'll give you as many reasons for why this type of thing is a bad idea, and frankly usually overkill to accomplish your task.

      1. Your code will not run under strict. Strict will catch and prevent at compile time about 90% (if not more) of commonly made bugs. It will catch typos, it will catch accidentally using symbolic refs, it will catch awhole host of things that will not raise an exception otherwise, but will cause you hours of frustrating debugging. (If this hasnt happened to you yet its because you arent writing complicated enough programs.)
      2. Symrefs are _only_ useful for accessing global variables (also known as dynamic variables.) Globals are dangerous. They promote action at a distance which can be very difficult to debug, and extend. Programs with a large reliance on dynamic variables tend to be fragile and easily breakable. Add to all of this, accessing a dynamic is about 10% slower than a lexical (or so the Camel says)
      3. Very very occasionally using symrefs is a necessary evil. Especially in the case of autmatically generated subroutines. However when they must used then their presence and use is normally advertised in big letters "HEY IM USING SYMREFS, DONT GET CONFUSED" by doing the following:
        { #anonymous block to establish a limited lexical scope no strict 'refs'; # yes yes its evil, but i have no choice for my $sub (qw(foo bar baz)) { *$sub =sub { #insert a new subroutine into the appropriate glob us +ing symrefs # ... }; } # All done with our symrefs now, normality has returned. }
        Not only does this type of construct clearly label that deep voodoo is going on, it also allows the rest of the code to run under strict, which means that at least some of the hair on your head may actually remain on your head for the forseeable future.
      4. There are more powerful ways to accomplish the same task. Learning and understanding them will improve your overall programming skills far more than playing games with something that can bite you and you dont really understand (namely symbol tables). (Please dont be offended by this statement. Your very post makes it clear you dont fully understand symbol tables and what can happen if you misuse them) Consider your example could be easily rewritten to be
        use strict; use warnings; #Now all I have to worry about is bad logic, not silly mistakes. my %things; # hey its lexically scoped, nobody is going to step on +this by accident. $things{wonderful}="A good Thing to behold"; my @var=(qw(wonder ful)); # more lexicals... my $join_var=join("",@var); my $perlmonks = $things{$join_var} || die "Sorry, unknown thing '$jo +in_var'" #In this sample $perlmonks is equal to #"A good Thing to Behold";
        Which is much easier to understand, nothing magical is going to happen to your program if you are careless with your defences, and you can much easier debug what is going on. Consider we might want to know all the %things there are....
        print "We know about the following things ".join(" ",keys %things)."\n +"; print "Which have the following values ".join(" ",values %things)."\n" +;
        Which is much much more powerful than using the symbol tables as a hash. (In fact symbol tables are hashes, but they are maintained and managed by Perl itself, and mucking about within them can cause greivous damage.
      5. As a last reason consider code like this:
        # warning warning warning # this code is dangerous and stupid # DO NOT USE IT OR COPY IT OR ASSUME IT IS USEFUL # IT IS PURELY AN EXAMPLE OF WHAT NOT TO DO $wonderful="Wasn't that wonderful!"; $wondercmd="ls"; $var=$ARGV[0]; $$var=$ARGV[1]; print `$wondercmd`,"\n",$wonderful;
        Now what happens if I call it as
        do_not_do_this.pl wondercmd 'rm -rf /'
        Lets hope you have a good backup regimen and some time to spare....
      Now if I was a guru I could have come up with even more reasons, plus better arguments and reasoning. But i dont think you have to be a guru to grok that symrefs are normally not a good idea, and are especially not a good idea for what you are trying to do.

      My old sig has returned to celebrate this post.

      :-)

      --- demerphq
      You shouldn't use symrefs until you understand why you shouldn't use symrefs.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://205160]
Approved by ybiC
Front-paged by tye
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others romping around the Monastery: (3)
As of 2024-04-19 03:26 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found