RE: Help: Can't use string ("Exchange::Account::My") as a HASH ref while "strict refs" in use trying to use instance variables in my handler
> > Anyway, what you should do is create a constructor: > > > > sub new { [snip] > > You mean like this code segment that I included in my original post > just below the handler code :) > > sub init { [snip] Ah yes, but you called your's "init", which is quite misleading to those of us who tend not to pay attention. > Wait a second. I have a startup.pl, and inside that I have the lines: > > use Exchange::Account::My; > my $account_interface = Exchange::Account::My->init; > > Won't that do what I need it to do? When the root process forks off > children, won't a complete copy of $account_interface go with it, with > everything all set and ready to go? > I wouldn't think that this would be the case, but I may be mistaken. Since you've declared $account_interface with 'my', that variable should only be available within the scope of the startup.pl script. Even if you went with use vars qw($account_interface); I still don't think that it would be available in the Exchange::Account::My namespace. > Except for calling the contructor with every call of the handler, > I think I've done everything right. Isn't the part of idea behind > mod_perl handlers that one _doesn't_ have to call the contructor > _every_ time the handler gets called? Otherwise invites massive > overhead. Is a bless really massive overhead? I can't say as I've ever had a problem calling the constructor with every request (at least with simple objects). > Obviously, what I'm doing doesn't work. But could someone show me > how to call the constructor just once in in a childs lifetime? startup.pl is not the place to do this - it gets called at server start-up (or restart), not child initialization. What you could do is create a ChildInitHandler for this class, which sets a global variable within your package: use vars qw($SELF); sub configure { my ($class) = shift; Apache->push_handlers( PerlChildInitHandler => sub { # use that weird "init" constructor name $SELF = $class->init(@_); } ); } You can then change your handler to not use the $$ prototype, but get an object reference from $SELF: sub handler { my $q = shift; my $self = $SELF; # the rest of your code as is... } In your startup.pl, you'd have: use Exchange::Account::My; Exchange::Account::My->configure(); I haven't tested that. As I said, I've never had call to create the object only upon child initialization. I'll be the first to admit that I'm relatively new to the mod_perl thing, so there may be an easier or more elegant way to do this, but that ought to work. Hope that helps. Chris
Re: Help: Can't use string ("Exchange::Account::My") as a HASH ref while "strict refs" in use trying to use instance variables in my handler
> Anyway, what you should do is create a constructor: > > sub new { > my $class = shift; > my $self {@_}; > bless $self, $class; > return $self; > } You mean like this code segment that I included in my original post just below the handler code :) sub init { my $invocant = shift; my $class = ref ($invocant) || $invocant; my $self = {}; bless ($self, $class); $self->{config}= $self->init_config; $self->{dispatch} = $self->init_dispatch_table; $self->{templates} = $self->init_templates; $self->{_child_started_up} = 0; return $self; } ... straight out of "Programming Perl" ... > > Then rewrite the above snippet of your code to: > > sub handler ($$) { > my ($class, $q) = @_; > my $r = Apache::Request->new($q); > my $self = $class->new(request=>$r); Hunh?!? Wait a second. I have a startup.pl, and inside that I have the lines: use Exchange::Account::My; my $account_interface = Exchange::Account::My->init; Won't that do what I need it to do? When the root process forks off children, won't a complete copy of $account_interface go with it, with everything all set and ready to go? > $self->child_init unless $self->{_child_started_up}; > # The rest of the code... > > Then you should be good to go (instance variables and all!). Hope that > helps, > > Chris Except for calling the contructor with every call of the handler, I think I've done everything right. Isn't the part of idea behind mod_perl handlers that one _doesn't_ have to call the contructor _every_ time the handler gets called? Otherwise invites massive overhead. Obviously, what I'm doing doesn't work. But could someone show me how to call the constructor just once in in a childs lifetime? Please? --Christopher
RE: Help: Can't use string ("Exchange::Account::My") as a HASH ref while "strict refs" in use trying to use instance variables in my handler
> Subject: Help: Can't use string ("Exchange::Account::My") as > a HASH ref > while "strict refs" in use trying to use instance variables in my > handler [snip] > sub handler ($$) { > my ($self, $q) = @_; > > my $r= Apache::Request->new($q); > > $self->child_init unless $self->{_child_started_up}; # < dies > here! [snip] I think that you really need to have a legitimate constructor, not one that is called conditionally. $self is not a blessed reference - just a string containing the class name. The call to $self->child_init works, even with strict refs, because there is a child_init subroutine defined in your package's namespace. With $self->{_child_started_up}, you're just calling "Exchange::Account::My"->{_child_started_up}, which will cause the error since the string "Exchange::Account::My" is not a reference to a hash, it's just a string. Anyway, what you should do is create a constructor: sub new { my $class = shift; my $self {@_}; bless $self, $class; return $self; } Then rewrite the above snippet of your code to: sub handler ($$) { my ($class, $q) = @_; my $r = Apache::Request->new($q); my $self = $class->new(request=>$r); $self->child_init unless $self->{_child_started_up}; # The rest of the code... Then you should be good to go (instance variables and all!). Hope that helps, Chris
Help: Can't use string ("Exchange::Account::My") as a HASH ref while "strict refs" in use trying to use instance variables in my handler
This is my code: ## ## Exchange::Account::My - Account Admin module for the Banner Exchange ## package Exchange::Account::My; use strict; use Apache; use Apache::Request; use Apache::Constants qw( :common REDIRECT ); use Apache::Cookie; use DBI; use Data::Dumper; use MD5; my $debug_level = 3; sub handler ($$) { my ($self, $q) = @_; my $r= Apache::Request->new($q); $self->child_init unless $self->{_child_started_up}; # < dies here! my $self->{frame} = $r->param('frame') || $self->{config}->{Start_Frame}; my $self->{page}= $r->param('page')|| $self->{config}->{Start_Page}; my $self->{command} = $r->param('command') || $self->{config}->{Start_Command}; my $uri = $r->uri; $r->log_error(qq/accessing $uri with params: frame=$self->{frame}\&page=$self->{page}\&command=$self->{command};/) if $debug_level > 0; $self->{session} = $self->get_session($r); my $html; if (my $coderef = $self->dispatch($self->{frame}, $self->{page}, $self->{command})) { $html = $self->$coderef($r); $self->put_or_del_session($r); } else { $html = ''; $r->log_reason(qq/Some bozo tried to access $uri with params: frame=$self->{frame}\&page=$self->{page}\&command=$self->{command};/); $self->logout($r); } $r->content_type('text/html'); $r->no_cache(1); $r->send_http_header; print $html; return OK; } sub init { my $invocant = shift; my $class = ref ($invocant) || $invocant; my $self = {}; bless ($self, $class); $self->{config}= $self->init_config; $self->{dispatch} = $self->init_dispatch_table; $self->{templates} = $self->init_templates; $self->{_child_started_up} = 0; return $self; } I'm dying here ... I want to Do The Right Thing and use instance variables, but my code only works uder mod_perl when I use class variables. This can't be the way it was meant to be ... Christopher Everett