Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked

Unexpected CGI param behavior

by cLive ;-) (Prior)
on Jun 24, 2008 at 00:30 UTC ( #693635=perlquestion: print w/replies, xml ) Need Help??
cLive ;-) has asked for the wisdom of the Perl Monks concerning the following question:

Well, unexpected to me...

#!/usr/bin/perl use strict; use warnings; use Data::Dumper 'Dumper'; use CGI; my $q = CGI->new(); my $var = { first => $q->param('first'), second => $q->param('second'), }; print Dumper($var);

What do you expect $var to be? I expected

$VAR1 = { 'first' => undef, 'second' => undef, };

What I got was:

$VAR1 = { 'first' => 'second' };

To me, this is unexpected behavior. This is the line that gives us this:

return unless defined($name) && $self->{$name};

Changing it to:

return undef unless defined($name) && $self->{$name};

gives me the behavior I expect. But, is there a reason why the line as it stands is more correct than my interpretation? Am I the only person who thinks that the current implementation feels wrong?

Replies are listed 'Best First'.
Re: Unexpected CGI param behavior
by pc88mxer (Vicar) on Jun 24, 2008 at 00:47 UTC
    I think CGI implements this behavior so that param() can support both scalar and list context. In list context it returns all the values for a parameter and in scalar context it just returns the first value.

    If it returned undef for unknown parameters, then this wouldn't work:

    my @vals = $q->param('...'); print Dumper(\@vals); # would print [ undef ] not [ ]
    That is, @vals would not be the empty list but a list containing undef.

    A work-around is to use scalar:

    my $var = { first => scalar $q->param('first'), second => scalar $q->param('second'), };
Re: Unexpected CGI param behavior
by NetWallah (Abbot) on Jun 24, 2008 at 00:54 UTC
    The fine manual says:
    If the parameter does not exist at all, then param() will return undef in a scalar context, and the empty list in a list context.
    (Emphasis mine)

    Essentially using the reasoning mentioned by pc88mxer.

    So this is a case of FAD (Functions as documented).

    ++ for identifying and documenting the issue clearly.

         "A fanatic is one who redoubles his effort when he has forgotten his aim."óGeorge Santayana

Re: Unexpected CGI param behavior
by runrig (Abbot) on Jun 24, 2008 at 00:42 UTC
    If there is more than one param with the same name in the query string, param() return a list of the values (which is documented behaviour)...and that would also mess up your hash array.
Re: Unexpected CGI param behavior
by ysth (Canon) on Jun 24, 2008 at 03:19 UTC
    For the reasons given by others, the implementation is correct. If you want, you could use:
    my $vars = CGI->Vars;
    (and then, if you want selected parameters, use $vars->{'first'}, etc.) which has a different icky way of dealing with multi-valued parameters.

    The correct param() invocation would be:

    { first => scalar $q->param('first'), second => scalar $q->param('second'), }
Re: Unexpected CGI param behavior
by cLive ;-) (Prior) on Jun 24, 2008 at 20:35 UTC

    Hmmm. I guess my beef is with the fact that param() is another victim of "wantarray madness".

    Ah well, live, learn and write explicit code to solve the issue...

      You have it backwards, as far as I'm concerned. Your snippet would still fail without wantarray. Without wantarray, my $scalar = $cgi->param('foo'); would *also* fail.

      That's the case for every function that returns a list. Perl can't return a list in scalar context, so param must necessarily return something different in scalar context. wantarray simply helps return a meaningful value instead of junk.

      Since param returns a list, feel free to always call param in list context if you want to avoid the issue.

      my @values = $cgi->param('foo'); my ($first_value) = $cgi->param('foo'); my $first_value = ( $cgi->param('foo') )[0];

        "would *also* fail" - um, no it wouldn't, because it explicitly returns a scalar undef. I've tested it.

        Of course, what it would do is change an array assignment:

        # from @array=(); # to: @array=(undef);

        Which would be an unacceptable change to existing behavior (exists $array[0] value would change from empty string to 1).

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://693635]
Approved by pc88mxer
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (7)
As of 2017-02-25 09:35 GMT
Find Nodes?
    Voting Booth?
    Before electricity was invented, what was the Electric Eel called?

    Results (365 votes). Check out past polls.