Michael Ludwig wrote:
Moin André,
Am 26.04.2010 um 21:44 schrieb André Warnier:
cr...@animalhead.com wrote:
The retention of values from previous executions applies
only to global variables.
Ah, yes.
But that would have triggered another discussion (which it might now
still do of course), about what exactly /is/ a global variable, in the
context of a mod_perl handler or perl script run under modperl::Registry.
Let's first clarify it for Perl in general, and then for mod_perl.
A global variable in Perl is any variable not declared with "my". Which includes variables declared with
"our" or "use vars" (I'll get to these), and also variables created by full qualification, as in
"$Bla::Blub = 1".
A lexical variable in Perl is any variable declared with "my", regardless of
the scope, which may be file-level. Unlike globals, lexical variables aren't directly
accessible from outside the package.
A global variable declared (or introduced, or admitted) with "use vars" is in scope for the entire
package where it is declared. A global variable declared with "our" is in scope only for the
lexical scope where it is declared (see "perldoc -f our").
(There's also "local", a misnomer, to temporarily stash away the current value
of a global variable and shadow it with another value. We can leave it out of the picture
here.)
Now, how is this different for mod_perl? Well, it isn't, if you think about it,
or rather it boils down to the difference between a mod_perl handler and your
typical batch script. Your batch script is invoked, it runs, and ends. Running
it probably includes some initialization code of yours placed at the file
level. Next time around, the whole thing start anew. Nothing special here.
A mod_perl handler, as you know, is loaded once, and unless it is reloaded, is
only acted upon by invocation of its functions, such as handler(). Which means
that reinitialization doesn't happen automatically, as with your batch script
running in a new process each time.
So what does this mean for file level lexical variables (my-variables) you have
defined? Well, they don't get reinitialized (unless you provide code to do so),
so they start behaving like global variables, retaining state between
invocations. They are not, however, accessible from outside the current
package, so they're still lexical variables.
There's one more thing to understand, especially in the context of Apache::Registry and Apache2::Registry,
and that's lexical "my" variables referenced from nested names subroutines. You do not usually
create nested named subroutines, but the Registry handler does it for you by wrapping your registry script in
a handler subroutine in a package made up from the filesystem path of rour registry script. So if you define
a registry script with a subroutine that references a lexical variable from the enclosing scope, you'll see
the familiar warning message "Variable "$x" will not stay shared".
You can read up about this issue here:
http://perl.apache.org/docs/general/perl_reference/perl_reference.html
Hope this helps :-)
Very nice. And it does help my understanding.
Although the key paragraph here, I would say, is :
So what does this mean for file level lexical variables (my-variables)
you have defined? Well, they don't get reinitialized (unless you provide
code to do so), so they start behaving like global variables, retaining
state between invocations. They are not, however, accessible from
outside the current package, so they're still lexical variables.
Let me give an example of how I understand this, for mod_perl handler
packages :
# -- start of code --
package My::Something;
my $lexical_mine;
sub access {
my $r = shift;
if (defined($lexical_mine) {
$r->log_error("in access: value present : $lexical_mine);
$lexical_mine++;
} else {
$lexical_mine = 1;
$r->log_error("in access: initialised to : $lexical_mine);
}
return OK;
}
sub response {
my $r = shift;
if (defined($lexical_mine) {
$r->log_error("in response: value present : $lexical_mine);
$lexical_mine++;
} else {
$lexical_mine = 1;
$r->log_error("in response: initialised to : $lexical_mine);
}
# .. generate some response for the browser
return OK;
}
sub finalise {
my $r = shift;
my $lexical_mine;
if (defined($lexical_mine) {
$r->log_error("in finalise: value present : $lexical_mine);
$lexical_mine++;
} else {
$lexical_mine = 1;
$r->log_error("in finalise: initialised to : $lexical_mine);
}
return OK;
}
# -- end of code --
Now if I configure the first of these subs as a PerlAccessHandler and
the second as a PerlResponseHandler, what happens to $lexical_mine ?
It might be lexical, in the sense that there is no way for code in
another file, to access this variable from outside as, for example,
$My::Something::lexical_mine
But for all intents and purposes, this variable is "functionally
global", in the sense that throughout the life of the Apache child that
contains this perl interpreter, this variable is "shared", not only by
the separate handler subs, but even by subsequent invocations of these
subs in the course of processing all HTTP requests which happen to be
processed by this Apache child.(*)
On the other hand, if I configure "finalise" as a PerlSomethingHandler,
then the $lexical_mine that is defined inside it, does not play along
with the other one. It is its own thing, and it will print its own
incremental sequence 1,1,2,3,4,5
But it is still "global" in a sense : while "private" to the sub
"finalise", it nevertheless is shared between consecutive invocations of
the same finalise() sub by the same Apache child.
So I guess what I mean is :
"global" and "lexical", as you use the terms above and as they are used
in the perl documentation (and no doubt rightly so), refer to scoping in
the sense of "how can I / can I not access that variable from outside of
the block/file where it is declared, using a "name" for it in my code.
However, for someone starting with perl and mod_perl, the term "global"
has a tendency to be interpreted as "shared between the handler subs
which I define in my package while they successively handle various
stages of one request", or even "shared between different invocations of
these handler subs for different requests", or even as "shared by all
handler subs processing all requests to this Apache".
(The last one being impossible with prefork).
So, back to the basics, my interpretation : by default, consider any
variable as "global/shared" and you'll generally stay out of trouble.
(*) which is going to be very confusing in the logfile however, as for
now there is no way to distinguish which child logs a message.
For that, we might want to add ($$) to the log messages.