in reply to My, subroutines, scope, and CGI – Why can I see a private (my) variable in a subroutine but it doesn’t get updated?

Why, if variables declared private using my shouldn’t be available in a subroutine, are they available in a subroutine?

The subroutine that you're testing with is defined inside the scope where the lexical variable exists. If you do something like this instead:

{ my $user_name=param('username'); print "IN SCRIPT: user_name == $user_name<br>\n"; login(); print "IN SCRIPT: user_name == $user_name\n"; } sub login { print "IN SUBROUTINE: user_name == $user_name<br>"; print "Can I change it in the subroutine?<br>"; $user_name = "Bill"; print "IN SUBROUTINE: user_name == $user_name<br>\n"; }

...then it won't even compile under strict because the sub refers to a variable ($user_name) that's not available in its scope. Put the login sub inside the braces that have my $user_name, and it will work again. See?

Why does my CGI script maintain information between executions?

This is something that mod_perl does.

Are there any other variable declarations I should know aside from my and local when using strict?

No. I general, you should almost always use my instead of local. If you want global variables, look at our or vars.

  • Comment on Re: My, subroutines, scope, and CGI – Why can I see a private (my) variable in a subroutine but it doesn’t get updated?
  • Select or Download Code

Replies are listed 'Best First'.
Re^2: My, subroutines, scope, and CGI – Why can I see a private (my) variable in a subroutine but it doesn’t get updated?
by Calm (Acolyte) on Apr 25, 2007 at 18:12 UTC
    Thanks for your response.

    ...then it won't even compile under strict because the sub refers to a variable ($user_name) that's not available in its scope. Put the login sub inside the braces that have my $user_name, and it will work again. See?

    I understand. It didn't sound that way from the book, but I understand and can adjust accordingly.

    This is something that mod_perl does.

    Can I stop it? Should I? Should I just reinitialize the variable in the subroutine the same way I do in the main script? Why does it do that?

    No. In general, you should almost always use my instead of local. If you want global variables, look at our or vars.

    Thank you, and will do.

      Re mod_perl keeping old values in scope:
      Can I stop it? Should I? Should I just reinitialize the variable in the subroutine the same way I do in the main script? Why does it do that?
      Mod_perl (or more precisely, Apache::Registry) converts scripts to subroutines so they can be re-used without recompiling. Basically, if you have a script like this:
      my $var = param('something'); sub print_var { print $var; } print_var();
      It will get converted to something like this:
      sub run_my_script { my $var = param('something'); sub print_var { print $var; } print_var(); }
      And you should get a Variable "$var" will not stay shared warning in your error log.

      AFAIK what happens is that in perl you can't really define named subroutines (like "print_var" here) inside another subroutine. If you try, you can run into scoping issues. In this case, if you call run_my_script() repeatedly, print_var() will always only see the first value of $var.

      One solution is to put most of your code in a module and use that from the script.

      Another is to remove the script entirely and write an request handler module that does whatever the script does.

      Update: yet another solution would be to not access the lexical variables available from the "higher up" scope inside your subroutines -i.e. pass everything needed as subroutine arguments instead. And pay attention to that error log :-)

      See also Exposing Apache::Registry secrets in the CGI to mod_perl porting guide.