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

Hello! I'm developing a module of useful web/db functions. Several of the functions need to use an existing DBI $DBH handle, and I'm trying to figure out the most stylish way to arrange this. Here are my constraints: I want to put the functions into a module that doesn't require any other modules except for CGI.pm. If I just pass in the $DBH through as one of the function args, that seems like a bit inefficient, since I _always_ need to pass it in.
example: my_function($DBH, @args)
The other possibility seems to be make the function an OO method, which gives me the syntax:
example: $DBH->my_function(@args)
That perhaps might look cleaner, but OTOH, it doesn't really save much typing per function call. So the question is, when developing a routine that's always going to need a object reference to be passed in, what's a good style to handle this in? Thanks.

Replies are listed 'Best First'.
Re: need help developing fly OO style
by btrott (Parson) on Aug 12, 2000 at 21:59 UTC
    Well, it depends. In your second code example, that makes it look as if you're calling my_function on your $DBH object. You can't do this unless you've defined my_function to be in the class into which your database handle is blessed (or in some ancestor of that class). In your case, that ancestor would be DBI. I'm not sure that inheriting from DBI would be particularly easy, considering that it relies on specific database drivers to do much of the work. So in that case, what exactly are you inheriting from: DBI or the database driver?

    Here's what I've done in the past, which makes it easier. I use a "has-a" relationship rather than an "is-a" relationship.

    I've created a My::DBI class (or something such). An object of type My::DBI contains a DBI database handle; but it's not actually a database handle itself. Every method that I call on my database handle is forwarded to a call on the database handle; before and after this forwarding I can do some processing on my own. For example (this code is untested, though it's based from memory on code I've written before, which *is* tested):

    package My::DBI; use strict; sub new { my $class = shift; bless { @_ }, $class; } sub connect { my $self = shift; return $self->{dbh} if defined $self->{dbh}; croak "Need connection parameters" unless defined $self->{connect}; my $c = $self->{connect}; ## Simplify typing :) return $self->{dbh} = DBI->connect ($c->{dsn}, $c->{user}, $c->{pass}, 'mysql', { RaiseError => 1 }); } sub my_function { my $self = shift; ## $DBH is now in $self->{dbh} } ...
    And so on. Usage:
    my $db = My::DBI->new(connect => { ... }); $db->my_function(@args);
    Would that work for you?
      Thanks btrott, After some contemplation, I don't think this is my ideal solution, though I can see it's benefit in other situations. Say for example my module I'm building is named CGI::SQL, I'd like it to have functions that use the $dbh, but it doesn't try to connect itself-- a connection is already assumed-- this gets me out of the business of managing the user's preferences for their connect string. maybe just passing in the $dbh as a normal function argument is the way to go?
Re: need help developing fly OO style
by chromatic (Archbishop) on Aug 12, 2000 at 22:27 UTC
    Another option is to pass the handle to your module's constructor, and have it stored as an element of the blessed hash (assuming you use a hash, that is). The drawback to this is that you'll have to create an instance of your class for each different database handle you need, though btrott's example has a similar weakness. (And it's not really a weakness.)
      This solution has it's merits as well. However for a small script that uses just one database handle but only 1 call to the module (let's say CGI::SQL), then I get a call like this: my $obj = new CGI::SQL($DBH); my $result = $obj->insert_sql_from_param; So, I end up writing two lines and making two calls where I might just make one with another solution. However, if I made lots of calls to CGI::SQL in my script, this overhead would be low and worthwhile. I'll consider working with this solution. Thanks!
Re: need help developing fly OO style
by tilly (Archbishop) on Aug 12, 2000 at 23:02 UTC
    I have faced almost this exact problem and solved it in a very different way. What I did is created a module which could export a call to give a connected database handle. This call would memoize the handle the first time and then return it as needed. I then called this as often as I wanted.

    Actual code is at RE: passing DBI database handles to subroutines. You really should follow the discussion with merlyn for a few issues to think about. The "won't stay shared" error we are discussing is pretty subtle but relevant to anyone who is thinking of using mod_perl. I understand it but I am not sure I know of any good way to explain it to someone else. But I took a shot at it anyways at RE (3): BrainPain-Help and nobody asked questions about it or seemed to think that any corrections were needed...