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

Hi, I've been messing around with the AUTOLOAD, specifically, loading subs from a database table. Everything's going fine, except for the past few week's i've been trying to add the ability to have mulitiple methods stored in the database, depending on how the method is called. I.e, as an instance $blah->hello(); or straight from the module Blah::hello(); I think that there's the third way of calling the sub from inside another database loaded sub with just hello(); How on earth can I detect how the function has been called from within the AUTOLOAD function? I know I can use ref() to check the first value of @_ to differentiate between $blah->hello() and Blah::hello(), but i'm having a mental block trying to work out what would happen if the function was called from an instance method, but passed an instance as the first parameter? Maybe this doesnt make sense and i've just been thinking about it for far too long, but if you can help, i'd be most grateful. The code's below. Thanks, Stephen
sub AUTOLOAD { my $self = shift; my $type = ref($self) || $self; return if $AUTOLOAD =~ /::DESTROY$/; my $name = $AUTOLOAD; $name =~ s/.*://; my $dbh = BSN::DB::connect(); my $sql = "select * from method_tbl where name='".$name."' and typ +e='".$self->{_type}."'"; my $sth = $dbh->prepare($sql); $sth->execute(); my $ref = $sth->fetchrow_hashref(); unless (exists $ref->{body}) { $sql = "select * from method_tbl where name='".$name."' and ty +pe='Default'"; $sth = $dbh->prepare($sql); $sth->execute(); $ref = $sth->fetchrow_hashref(); unless (exists $ref->{body}) { return "Can't access `$name' method in class ".$self->{_ty +pe}; } } my $call = eval("$ref->{body}"); if ($@) { croak "Method Error: $@ in method `$name' in class $type"; } unshift @_,$self; goto &$call; }

Replies are listed 'Best First'.
Re: AUTOLOAD detecting the type of method call.
by MZSanford (Curate) on Sep 20, 2001 at 12:53 UTC
    Hmmmmmm, based on the info from caller() and the arguments, i think that the following can be said for what information is available :
    $obj->blah(); == PKG::blah($obj); &blah(); # in PKG == PKG::blah();
    But, the two sets are not equal (based on the first parameter ref(), as you said). There may be a way using caller() to get the calling package, which is why i specified &blah(); # in PKG, because, if exported, it is possible that the last caller would be in main::. The only other way to really tell, i would think, would be to pass a parameter which specifies, but that just sucks.
         There be a way i have missed, and i will definitly be watching this node for updates.
    my own worst enemy
    -- MZSanford
Re (tilly) 1: AUTOLOAD detecting the type of method call.
by tilly (Archbishop) on Sep 20, 2001 at 16:25 UTC
    To the best of my knowledge there is no way to do what you want other than through some kind of heuristic. The simplest of which is to check whether the first argument is reasonable. Another trick would be to have the name of the class not match the name of the file (for instance it is a simpler version of it) but also offer functions that can be exported from Exporter using @EXPORT_OK (which is set by a query for available functions). Then tell people they can import functions or call methods, and they will be distinct because they are in different packages.

    However all of that said, I would step back and ask why you want to do this. If you succeed it has to be through some complex trickery which makes your code harder to understand, and I don't see that the flexibility adds that much for the person using this code. In other words in your position I probably would simply not add the feature, and then I would call the problem solved.

    BTW some tips. Creating a new connection for every single function call is painfully slow so I hope your function is returning the same connection each time. If you cannot find a method, you should croak or confess, not return a message. In fact I don't see that you will ever reach that error since if your table meth_tbl has a body field, you will always have that key in your hash.

Re: AUTOLOAD detecting the type of method call.
by perrin (Chancellor) on Sep 20, 2001 at 17:55 UTC
    Don't put your code in the database! You will regret it!

    I used to have to use this horrible tool called the Illustra Web Datablade. It kept all the code in a database table. As a result, I had to edit the code in a browser text area! This is about as painful as editing gets.

    My advice is to avoid storing anything you will need to edit with a decent editor in the database. Put it in the file system instead.

Re: AUTOLOAD detecting the type of method call.
by metcals1 (Acolyte) on Sep 20, 2001 at 18:24 UTC
    Thanks for the suggestions.

    The direction i was going with the check was so that there could be different methods in the table that handle the different types of call (or all of them).

    The eventual aim of this code is to have a client tool which talks directly to the database to modify the code, in a similar manner to vignette story server (but with perl instead of TCL).

    At the moment the working code lets you store objects in the database, (that at the moment can be html, data (using Data::Dumper) and straight perl code. You can then write various subs that act upon the different types of object, such as the edit sub, which lets you edit (by means of a form at the moment) the object. The sub then passes the result of the form back to itself.

    At the moment this is fairly slow, but I think that after it's implemented with mod_perl, I can use caching (and possible storage of byte-code) to reduce the database calls and the number of eval's needed in a typical.

    The eventual aim of this is to allow the rapid development of dynamic sites.

    Thanks for your comments.

    Stephen