Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Accessing Variables in Different Subroutines

by stefl (Acolyte)
on Mar 19, 2015 at 15:19 UTC ( [id://1120590]=perlquestion: print w/replies, xml ) Need Help??

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

Hi Monks, I am trying to use the value of a string in multiple subroutines. I kind of see this as two problems (or rather, things I don't yet understand):
1 - If I instantiate a variable outwith the subroutines and give it a value in one subroutine, I am unable to get that value in subsequent subroutines.
2 - If I use a random string and use it in each subroutine, it has a different value in each subroutine. Is there any way to keep it static?
Code is given below. I have a feeling it's something really simple...
Thanks very much for any help!

#!/usr/bin/perl use strict; use warnings; no warnings "uninitialized"; use CGI ":standard"; # I have also tried: # my @chars = ("A".."Z", "a".."z", "0".."9"); # my $randomString; # my $file; # with the starred section (lines 38-41) # but this does not work - the variables are empty in subsequent subro +utines. # I have tried using 'our' rather than 'my' but no effect. ################################################# # The below variables are the ones that I would like to use in multipl +e subroutines ($randomString and $file) ################################################# my @chars = ("A".."Z", "a".."z", "0".."9"); my $randomString; $randomString .= $chars[rand @chars] for 1..8; my $file = $randomString.".txt"; # Initial variables my @languages = ("English", "Francais"); my @colours = ("Red", "Orange", "Yellow", "Green", "Blue", "Indigo", "Violet", "Black"); my %dispatch = ( default => \&select_language, select_color => \&select_color, select_animal => \&select_animal ); my $action = param("action"); my $execute = $dispatch{$action} || $dispatch{default}; $execute->(); exit; sub select_language { #**********# # $randomString .= $chars[rand @chars] for 1..8; # $file = $randomString.".txt"; #**********# print header(), start_html(), h2("Welcome to this basic form"), startform(), hidden({ -name => "action", -value => "select_color", -override => 1 }), popup_menu({ -name => "language", -values => \@languages, -default => $languages[0] }), p("The randomly generated string is: $randomString<br>The file +name is: $file"), submit({-value => "Continue"}), endform; } sub select_color { print header(), start_html(), h2("Part Two"), startform, p("The randomly generated string is: $randomString<br>The file +name is: $file"), hidden({ -name => "action", -value => "select_animal", -override => 1 }), hidden({ -name => "language" }), "<p>Please choose your favourite colour: </p>", radio_group({ -name => "colour", -values => \@colours, -default => $colours[0], -linebreak => "true" }), submit({-value => "Continue"}), endform; } sub select_animal { print header(), start_html(), h2("Almost Done!"), startform(), p("The randomly generated string is: $randomString<br>The file +name is: $file"), hidden({-name => "language"}), hidden({-name => "colour"}), p("Thanks for your help!"), endform; }

Replies are listed 'Best First'.
Re: Accessing Variables in Different Subroutines
by sauoq (Abbot) on Mar 19, 2015 at 18:42 UTC
    1 - If I instantiate a variable outwith the subroutines and give it a value in one subroutine, I am unable to get that value in subsequent subroutines.

    You are only calling one subroutine per execution. This should be obvious to you because you call it with $execute->(); and immediately thereafter, you exit;.

    The mistake you are making is pretty common for people who are brand new to web development. You are thinking that multiple calls to your CGI script are handled within one execution of the script. That's not the case. The script is executing anew each time you submit your form.

    There are different ways around this, but the most common one is to use a cookie to maintain state. Although you can store the state information directly in the cookie, that's not a very robust way to do it. A better way is to store the data on the server somewhere (often in a database) and then use the cookie as a key to get to that data.

    -sauoq
    "My two cents aren't worth a dime.";

      Thanks very much. As you can guess, I only started looking at web development just over a week ago, so I'm very much a beginner. Your answer explained my mistake very well, thanks!
      I managed to get around my problem by using hidden parameters (I'd tried this previously but incorrectly and just assumed that it didn't work) and now my script does what I need it to.
      If I start needing to do more web development than I am just now, I'll have a deeper look into other options (but for now this works!)

Re: Accessing Variables in Different Subroutines
by choroba (Cardinal) on Mar 19, 2015 at 15:45 UTC
    I can't replicate your problem. I added a "both" action to the dispatch table that calls both the subroutines:
    both => sub { select_language(); select_animal(); }

    Then I ran your code with action=both and lo and behold! The value was the same in both the subroutines.

    Do you expect the value to be the same for different runs of the script?

    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

      I'm expecting it to be different in different runs of the script, but the subroutines need to be run sequentially (this is a much-simplified example of my code). When you run this script as it is, do the $randomString and $file variables have the same value throughout the form? For me the values change after each "Continue".

        Sure, because clicking "Continue" runs the script again. You should read more on HTTP.
        لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: Accessing Variables in Different Subroutines
by marinersk (Priest) on Mar 19, 2015 at 15:35 UTC

    Lexical scoping is your friend:

    I think this will demonstrate what you're looking for?

    #!/usr/bin/perl use strict; my $tossMeAbout = 'Initial value'; { my $updatedValue = &adjustValue($tossMeAbout); print "----------------------------------------------------------- +--------------------\n"; print " MAIN: \$tossMeAbout = [$tossMeAbout]\n"; print " MAIN: \$updatedValue = [$updatedValue]\n"; my $additionalValue = &adjustValue($updatedValue); print "----------------------------------------------------------- +--------------------\n"; print " MAIN: \$tossMeAbout = [$tossMeAbout]\n"; print " MAIN: \$updatedValue = [$updatedValue]\n"; print " MAIN: \$additionalValue = [$additionalValue]\n"; print "----------------------------------------------------------- +--------------------\n"; } exit; { my $persistentValue; sub adjustValue { my ($requestedValue, @garbage) = @_; if (!defined $requestedValue) { $requestedValue = ''; } my $returnValue = ''; print "------------------------------------------------------- +------------------------\n"; print "SUB BEGIN: \$requestedValue = [$requestedValue]\n"; print "SUB BEGIN: \$persistentValue = [$persistentValue]\n"; print "SUB BEGIN: \$returnValue = [$returnValue]\n"; # Append requested value to persistent value if (!defined $persistentValue) { $persistentValue = $requestedValue; } else { $persistentValue .= "/$requestedValue"; } $returnValue = "<$requestedValue>"; print "------------------------------------------------------- +------------------------\n"; print " SUB END: \$requestedValue = [$requestedValue]\n"; print " SUB END: \$persistentValue = [$persistentValue]\n"; print " SUB END: \$returnValue = [$returnValue]\n"; return $returnValue; } } __END__

    Results:

    C:\Steve\Dev\PerlMonks\P-2015-03-19@1121-Durable-Subroutine-Data>persi +stent1.pl ---------------------------------------------------------------------- +--------- SUB BEGIN: $requestedValue = [Initial value] SUB BEGIN: $persistentValue = [] SUB BEGIN: $returnValue = [] ---------------------------------------------------------------------- +--------- SUB END: $requestedValue = [Initial value] SUB END: $persistentValue = [Initial value] SUB END: $returnValue = [<Initial value>] ---------------------------------------------------------------------- +--------- MAIN: $tossMeAbout = [Initial value] MAIN: $updatedValue = [<Initial value>] ---------------------------------------------------------------------- +--------- SUB BEGIN: $requestedValue = [<Initial value>] SUB BEGIN: $persistentValue = [Initial value] SUB BEGIN: $returnValue = [] ---------------------------------------------------------------------- +--------- SUB END: $requestedValue = [<Initial value>] SUB END: $persistentValue = [Initial value/<Initial value>] SUB END: $returnValue = [<<Initial value>>] ---------------------------------------------------------------------- +--------- MAIN: $tossMeAbout = [Initial value] MAIN: $updatedValue = [<Initial value>] MAIN: $additionalValue = [<<Initial value>>] ---------------------------------------------------------------------- +---------

Re: Accessing Variables in Different Subroutines
by jeffa (Bishop) on Mar 19, 2015 at 21:22 UTC

    You should check out Perl Dancer. It is a micro framework that has session support built in, which allows you to preserve values across otherwise unconnected HTTP requests. I took a little liberty with your code and "ported" it over to work in a Dancer framework. Using templates is a better choice but CGI.pm still works -- you just want to be sure and not use the header() function, as Dancer will send that data for you. I will confess that i could not get this code to work with POST requests, only GET requests. That can be an exercise for the viewer. :) The issue has something to do with CGI.pm defaulting to "multipart/form-data" enctypes ... and since you really should use templates instead of CGI.pm the right thing to do is modify this code to use templates.

    Also, don't forget to edit your config.yml file in your Dancer project to turn session handling on. Have fun!

    package My::App; use Dancer ':syntax'; use CGI qw(:all); our $VERSION = '0.1'; # Initial variables my @chars = ("A".."Z", "a".."z", "0".."9"); my $randomString; $randomString .= $chars[rand @chars] for 1..8; my @languages = ("English", "Francais"); my @colours = ("Red", "Orange", "Yellow", "Green", "Blue", "Indigo", "Violet", "Black"); get '/' => sub { session random_str => $randomString; my $random_str = session 'random_str'; my $file = "$random_str.txt"; return start_html() . h2("Welcome to this basic form") . start_form( -action => 'select_color', -method => 'GET' ) . popup_menu({ -name => "language", -values => \@languages, -default => $languages[0] }) . p("The randomly generated string is: $random_str<br>The filena +me is: $file") . submit({-value => "Continue"}) . end_form() . end_html() ; }; get '/select_color' => sub { my $random_str = session 'random_str'; my $file = "$random_str.txt"; return start_html() . h2("Part Two") . start_form( -action => 'select_animal', -method => 'GET' ) . p("The randomly generated string is: $random_str<br>The filena +me is: $file") . hidden({ -name => "language", -value => params->{language} }) +. "<p>Please choose your favourite colour: </p>" . radio_group({ -name => "colour", -values => \@colours, -default => $colours[0], -linebreak => "true" }) . submit({-value => "Continue"}) . end_form() . end_html() ; }; get '/select_animal' => sub { my $random_str = session 'random_str'; my $file = "$random_str.txt"; return start_html() . h2("Almost Done!") . start_form() . p("The randomly generated string is: $random_str<br>The filena +me is: $file") . hidden({-name => "language", -value => params->{language}}) . hidden({-name => "colour", -value => params->{colour}}) . p("Thanks for your help!") . end_form() . end_html() ; }; true;

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    

      ...I will confess that i could not get this code to work with POST requests, only GET requests....get '/' => sub { ... get '/select_color' => sub { ... get '/select_animal' => sub { ...

      get is get, post is post, any is any of http methods get/put/post/delete

      just get/post is  any ['get', 'post'] => sub { ...

Re: Accessing Variables in Different Subroutines
by GotToBTru (Prior) on Mar 19, 2015 at 15:32 UTC

    Please be more specific. Which variables, under what conditions, with what inputs?

    Dum Spiro Spero

      I've tried to edit the code I've provided to be more specific but I don't really know what you mean. I have 2 variables, $randomString and $file and I would like them to have the same values in each subroutine. The code I've provided is a cgi script (functioning) and illustrates the these variables have different values in each subroutine.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (6)
As of 2024-04-23 10:15 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found