Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I have been working on a class to create and check forms automatically. The problem is that, in case of a select field, the post variable can be a scalar or a hash depending on if the select field is a multiple one... is there any way to check if the variable passed to the program is a hash or a scalar???

and secondly, do i need to reset a hash if i ever need to access one if its key, value pairs after a loop?

janitored by ybiC: Retitle from one-word "hashes" to avoid hindering search results, minor format tweak for legibility

Replies are listed 'Best First'.
Re: hashes
by halley (Prior) on Jun 07, 2004 at 18:16 UTC
    A variable can't "be a hash or a scalar," but could contain a value called a "reference;" a reference can point to just about any perl entity or data type.
    my $val = func(); print "Reference to a HASH!\n" if ref($val) eq "HASH"; print "Reference to a ARRAY!\n" if ref($val) eq "ARRAY"; print "Reference to a SCALAR!\n" if ref($val) eq "SCALAR"; print "A non-reference SCALAR!\n" if not ref($val);
    The above will work if the value returned isn't actually blessed into a package; if that's a possibility, then you might want to check out isa() instead.

    --
    [ e d @ h a l l e y . c c ]

Re: hashes
by cyocum (Curate) on Jun 07, 2004 at 18:31 UTC

    You can always use the ref function to see what kind of reference a scalar is. It also returns the package name if the reference is an object, which makes it something like Java's instanceof operator.

    The second part of your question is confusing to me. If you access a value by key then you can do so again later. I hope I understand the second part of your question and I hope this helps.

Re: hashes
by shemp (Deacon) on Jun 07, 2004 at 18:37 UTC
    To answer your question about resetting a hash to access one of its key value pairs...that could be interpreted in a variety of ways.
    Restting a hash i usually interpret as:
    %my_hash = ();
    Which would delete all the key-value pairs, which i highly doubt is what you want.

    You are probably thinking of the key iterator needing to be reset. When you traverse the keys in a hash using keys, each, or values, the hashes internal iterator is used to keep track of what key to return next. There is only 1 iterator in a hash, not 1 for each type of operation. But, generally you dont need to worry about this if you are using keys or values, becuase they always iterate through the hash all at once, although it may not look like that in your program. (more details can be found in various docs)

    When you use each though, only the *next* key / value pair is returned, and the iterator is somewhere in the *middle* of the key list. So if you have a loop using each and it exits before traversing the entire hash, the iterator will not be put back to the start of the key list. This is the only time that you would generally need to reset the iterator. One way to do this is simply:
    keys %myhash;
    That may be more info than you wanted. But accessing a key or value in a hash has nothing to do with the key iterator.

    That said, if you do add or delete keys during a loop, you may get some unexpected behaviour in the loop.
Re: hashes
by jdporter (Paladin) on Jun 07, 2004 at 18:35 UTC

    It would help if you would post the code you're having trouble with.

    In answer to your second question: If you are accessing specific entries in the hash, there is no need to reset anything. You can, for example, access $foo{'bar'} as many times as you wish, without any surprises.
    On the other hand, if you're iterating over a hash using the each operator and you decide you want to start over before you've gone through all the entries, you can reset the iterator. This is detailed in the documentation of each.

Re: hashes
by kragen (Sexton) on Jun 07, 2004 at 19:00 UTC
    What's parsing your POST data? Neither CGI.pm nor CGI::Lite gives you a hash for a multiple select.

    I recommend using an interface that always gives you back the same thing, if possible. For example, CGI::param in list context returns a list of the values associated with that param, whether there's zero, one, or several values. This avoids adding special cases to the code that's calling it.

      " What's parsing your POST data? Neither CGI.pm nor CGI::Lite gives you a hash for a multiple select." Hmmmm.. I used CGI.pm to retrive the post variables. If it returns a list, it is a big problem for me because i need keys to keep options highlighted in the menu in case of any error, missing values... I posted my code below... Inside the check function I included php functions (i have no idea about their perl equivalents) named "is_array" and "empty" to indicate where i need to check the post variable... I am new to Perl, and I translated this code from a php class that i have created for my projects. So it might have a lot of flaws that i am not aware of... THanks a lot for the responses...
      # this is the sub that creates the select menu sub elementSelect { my($self,$nm)=@_; # unique keys are data/sql, default # I use data key to create static select menus # sql key to create dynamic menus from tables my $data_array; my $row; my $multiple="no"; my $select=undef; if($self->{ELEMENTS}->{$nm}->{data}){ $data_array=$self->{ELEMENTS}->{$nm}->{data}; }elsif($self->{ELEMENTS}->{$nm}->{sql}){ my $sql=$db->prepare($self->{ELEMENTS}->{$nm}->{sql}); $sql=$db->execute(); while($row=$sql->fetchrow_arrayref){ $data_array->[$row->[0]]=$row->[1]; } } $multiple="yes" if defined $self->{ELEMENTS}->{$nm}->{attributes}->{ +multiple}; $select="<select name='".$nm; if($multiple eq "yes"){ $select.="[]"; } $select.="' ".$self->getAttributes($nm).">"; if($multiple eq "no"){ $select.="<option value=''>select ".$self->{ELEMENTS}->{$nm}->{def +ault}."</option>"; } if($multiple eq "yes"){ while(my($key,$value)=each(%{$data_array})){ my $selected; if(($self->{PVARS}->{$nm} && $self->{PVARS}->{$nm}->{$key}) || ( +!$self->{PVARS}->{$nm} && $self->{VARS}->{$nm}->{$key})){ $selected="selected"; }else{ $selected=""; } $select.="<option value='".$key."' ".$selected.">".$value."</opt +ion>"; } }else{ while(my($key,$value)=each(%{$data_array})){ my $selected; if(($self->{PVARS}->{$nm} && $key eq $self->{PVARS}->{$nm}) || + (!$self->{PVARS}->{$nm} && $key eq $self->{VARS}->{$nm})){ $selected="selected"; }else{ $selected=""; } $select.="<option value='".$key."' ".$selected.">".$value."</optio +n>"; } } $select.="</select>"; return $select; } ##################################################### # DATA VALIDATION FUNCTIONS # this is where i have the problem, the checkRequired sub # should be compatible with both single values and lists in # case of multiple selects ###################################################### sub checkRequired { my($self,$nm)=@_; my $o=""; if(is_array($self->{POST}->param($nm))){ # check for multiple select if(empty($self->{POST}->param($nm))){ # check the array has any values in it # maybe if(self->{POST}->param($nm))??? push @{$self->{ERRORS}},"Please enter ".$self->{ELEMENTS}->{$nm} +->{message}."!"; }else{ $o=$self->{POST}->param($nm); } }else{ # value is scalar if($self->{POST}->param($nm) eq ""){ push @{$self->{ERRORS}},"Please enter ".$self->{ELEMENTS}->{$nm} +->{message}."!"; }else{ $o=$self->{POST}->param($nm); } } return $o; }