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

Hello esteemed colleagues.

I have an odd problem for you this morning. I am trying to implement a library system to make apache response handlers easier to get cranked out.

The idea is that the superclass has the actual handler() sub that apache calls, and it calls two basically empty subs in itself during it's handler call - one for config info, and one for the actual handler (but it's named something other than handler). The subclasses inherit all three subs I just mentioned from the parent class, and they are supposed to override the two empty ones with information that gets their job done, and allows me to factor out the common elements into the base class.

It looks something like this in the parent class:

sub handler { my $r = shift; my $err = ErrorTracker->new; # ... setup stuff my $args = validate_args($r, wrapped_handler_args()); $r->content_type('text/plain'); eval(wrapped_handler($r,$args,$err)); print $err->dumpHtml if $@; # shutdown / error handling stuff return $err->apacheStatus(); } sub wrapped_handler { print "inheritance is broken"; } sub wrapped_handler_args { return {}; }

Using @ISA works when apache calls the child class's missing handler() 'method', even though there's no object / $self being passed around at that point. It works well enough to be calling the base class's handler properly - apparently it 's fine with just rerouting subroutine calls in an OO manner regardless of arguments used.

Here's the problem. I am finding that the parent class can't access the child class because I am losing it's class name when perl does the @ISA search. I can't control the way mod_perl is calling the handler (or at least I don't want to for this project, I enjoy using a stock mod_perl.)

All I need is a way to find out what the class that originally got called before @ISA got involved. I am trying to avoid resorting to a hardwired routing table in the code, when the class name should be available to the runtime environment.

Is there such a way?

Maybe in some undocumented method of the apache request rec?
Or in some obscure perl system variable in the inheritance mechanism?
Or, if I had a variable like $AUTOLOAD (inside the AUTOLOAD subroutine) available to tell me the class that apache actually originally called, that would work. But I tried it, and it's not there for me when I need it.

I plead for enlightenment. Any hints or past experiences also welcome.

Thank you.

PS - For the record, adding an object to pass around doesn't solve the original problem - and I'm not opposed to it - but I still need to create said object inside of the handler() call of the base class. And it wasn't called in an object oriented context, so I don't know the class to create it as.

Replies are listed 'Best First'.
Re: Class Inheritance without an instance
by dave_the_m (Monsignor) on Oct 13, 2005 at 11:32 UTC
    It's not clear to me what problem you are trying to describe. Perhaps it would help if you showed a concrete example? For example, what is different about what you're trying to do, from that in the code below which correctly prints the name of the subclass?
    package A; sub foo { print "$_[0]\n" } package B; @ISA = qw(A); package main; B->foo(); __END__ $ perl /tmp/p B

    Dave.

      Here is the difference from your code:

      I am stuck with this kind of call:

      package main; B::foo();
      rather than this kind:
      package main; B->foo();
      which would be the same in practice (I believe) as:
      package main; B::foo(B);
      My problem is that neither the class name nor an instance are being passed. But it's still originally called as B::foo, so when I get to A::foo, it seems like it should be _somewhere_ that it was B::foo at first.

        B::foo(B) does not invoke inheritance. If A::foo ends up being executed, then it's not as a direct result of calling B::foo(B).

        (The slight exception to the the above is that AUTOLOAD is still inherited for non-method calls, although it's deprecated:

        package A; sub foo { print "A::foo called\n" } sub AUTOLOAD { print "A::AUTOLOAD called, \$AUTOLOAD=$AUTOLOAD\n" } package B; @ISA = qw(A); package main; B::foo('B'); __END__ $ perl /tmp/p Use of inherited AUTOLOAD for non-method B::foo() is deprecated at /tm +p/p line 11. A::AUTOLOAD called, $AUTOLOAD=B::foo $

        Dave.

        If B inherits A, and B::foo isn't defined, but A::foo is, calling B::foo will fail. There's no such sub.

        If you want Perl to act in an OO way, you should make a method call, not a sub call. Use B->foo, and A::foo will be called.

        If you can't or won't, you're out of luck.

        use strict; use warnings; $| = 1; sub A::foo {print "This is A::foo\n"} @B::ISA = qw /A/; print "Calling B->foo(): "; B->foo(); print "Calling B::foo(): "; B::foo(); __END__ Calling B->foo(): This is A::foo Calling B::foo(): Undefined subroutine &B::foo called at ...
        Perl --((8:>*
        That was my best idea, given my understanding of mod_perl, but now i'm not as sure. I just tested what I did above and got an error that wasn't present in the apache logs. The interface is the same as any other mod_perl handler:

        sub handler { my $r = shift; my $err = ErrorTracker->new; # ... setup stuff my $args = validate_args($r, wrapped_handler_args()); $r->content_type('text/plain'); wrapped_handler($r,$args,$err); # shutdown / error handling stuff return $err->apacheStatus(); } sub wrapped_handler { print "inheritance is broken"; } sub wrapped_handler_args { return {}; }
Re: Class Inheritance without an instance / $AUTOLOAD equ
by friedo (Prior) on Oct 13, 2005 at 15:21 UTC
    If you built your mod_perl with PERL_METHOD_HANDLERS=1 then in your configuration you can do:
    PerlHandler Your::Subclass->handler
    That will perform a method call on your class and inherritence will work as normal. More here.
      That looks like a perfect solution. And they are included by default in mod_perl2 (which I'm using).

      Thank you!

      A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Class Inheritance without an instance / $AUTOLOAD equ
by rinceWind (Monsignor) on Oct 13, 2005 at 12:05 UTC

    I don't have much knowledge of Apache and mod_perl, but what you are trying to do might be similar to something I have achieved.

    Take a peep into the guts of Module::Optional. This does dynamic importing of subs the first time they are called (via AUTOLOAD).

    --

    Oh Lord, won’t you burn me a Knoppix CD ?
    My friends all rate Windows, I must disagree.
    Your powers of persuasion will set them all free,
    So oh Lord, won’t you burn me a Knoppix CD ?
    (Missquoting Janis Joplin)