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

Hello Monks,

I would like a CGI script to execute different subroutines based on the value of the variable 'button'. I would also like to pass some other variables to the subroutines and process them.

Note that I pass the same set of variables to both the subroutines, but locally assign them to different variable names. Please provide your suggestions on the approach I have followed.

... use CGI; .... # Query all variables my $button = $query->param( "button" ); my $username = $query->param( "user" ); my $region = $query->param( "region" ); my $var1 = $query->param( "var1" ); my $var2 = $query->param( "var2" ); my $var3 = $query->param( "var3" ); if ( $button eq 'first' ){ display_first( $username, $region, $var1, $var2, $var3 ); } if ( $button eq 'second' ){ display_second( $username, $region, $var1, $var2, $var3 ); } ... ... sub display_first{ my ( $s1_username, $s1_region, $s1_var1, $s1_var2, $s1_var3 ) = @_ +; ..... ..... do something with the variables... ..... } sub display_second{ my ( $s2_username, $s2_region, $s2_var1, $s2_var2, $s2_var3 ) = @_ +; ..... ..... do something with the variables... ..... }

Replies are listed 'Best First'.
Re: CGI: Passing variables to a subroutine
by Herkum (Parson) on Jan 04, 2007 at 21:29 UTC

    To much work!

    use CGI; my $query = CGI->new(); if ($query->param( "button" ) eq 'first') { display_first( $query ) } else { display_second( $query ) } sub display_first { my $query = shift; # declare your variables here } sub display_second { my $query = shift; # declare your variables here }

    There is no reason to declare all your variables when they are already in the $query object. Just pass the query object and in the routine assign values to the variables as you need them. No more, no less.

      There is no reason to declare all your variables when they are already in the $query object.

      This generates a warning (uninitialized value in string eq) when button does not already exist in the $query object.

      my $query = CGI->new(); if ($query->param( "button" ) eq 'first') { display_first( $query ) }
      Declaring variables helps keep track of what input is expected and set default values when none exists:
      my $region = $query->param( "region" ) || 42; my $button = $query->param( "button" ) || ''; if ($button eq 'first') { # '' gives no warning
      This generates a different warning (uninitialized value in hash element):
      my $handler = $handlers{$query->param( "button" )};

      Thanks for the response

      If I have to pass other variables that are not a part of the $query object, I presume that I should be passing that to the subroutine.

      Please look at the modified code below:- Any suggestions?

      use CGI; my $query = CGI->new(); # get the data structure my $ref_data= create_data_structure(); if ($query->param( "button" ) eq 'first') { display_first( $query, $ref_data ) } else { display_second( $query, $ref_data ) } sub display_first { my ( $query, $s1_data ) = @_; # declare your variables here ... # use $s1_data to do something in this sub } sub display_second { my ( $query, $s2_data ) = @_; # declare your variables here ... # use $s2_data to do something in this sub } sub create_data { ... create a hash data structure ... ... return \%hash; }

        Use a dispatch handler.

        my %handlers = ( first => \&display_first, second => \&display_second, ... ); my $handler = $handlers{$query->param( "button" )}; if (!$handler) { ... } $handler->($query, $region, $var1, $var2, $var3);

        You might even want to make some of those variables global, especially if they aren't changed after being set. Alternatively, the handler could use $query to get the variables it needs.

        You don't actually need to pass $ref_data as an argument to your subroutines, because they're already in its lexical scope. (They can "see" it already.)

        But, it's good practice to keep the scope of things as small as possible, so why not just call create_data() in each of the subroutines where you need it? (Presumably, only one of them will be running per CGI request anyway.)

        And I second the suggestion of using a dispatch table. There's also CGI::Application, which is like a dispatch table on steroids with all sorts of nifty OO stuff and plugins.

Re: CGI: Passing variables to a subroutine
by Fletch (Bishop) on Jan 04, 2007 at 21:52 UTC

    Use the site search functionality to look for "dispatch table" (and seconding on the recommendation to just pass your $query instance).