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

Hello -

I'm attempting to create a package to handle/extend DBI functionality. I would love it if the following code would work as expected:

package mydbh; @ISA = qw( DBI ); require DBI; use strict; sub new { my( $class, $dns, $username, $password ) = @_; my $self = DBI->connect( $dns, $username, $password ); return bless $self, $class||ref $class; }
... however, it's not. The following code DOES work, but it's not exactly suiting my needs:
package mydbh; @ISA = qw( DBI ); require DBI; use strict; sub new { my( $class, $dns, $username, $password ) = @_; my $ref = DBI->connect( $dns, $username, $password ); return bless { DBI => $ref }, $class||ref $class; }
Anybody out there know what's going on?

Replies are listed 'Best First'.
Re: inheritance not working as expected
by bikeNomad (Priest) on Jul 03, 2001 at 19:50 UTC
    DBI seems to play some tricks with inheritance. When you call connect, you get an object that is blessed into a different class (i.e. not DBI). So your attempt to inherit from DBI is not giving you the desired inheritance.

    One possible way to handle this is to push the class of the returned value from connect on your own @ISA:

    package mydbh; @ISA = qw( DBI ); require DBI; use strict; sub new { my( $class, $dns, $username, $password ) = @_; my $self = DBI->connect( $dns, $username, $password ); push (@ISA, ref($self)) if (not grep { $_ eq ref($self) } @ISA); return bless $self, $class; }

    Also, I don't like dual-mode constructors (i.e. the bless $self, $class||ref $class stuff). Usually, you want to do something different if you're cloning an existing object (i.e. not just copy its class). In this case, you would probably want to clone the handle.

Re: inheritance not working as expected
by converter (Priest) on Jul 03, 2001 at 19:56 UTC

    I ran into this just the other day. &DBI::connect returns a blessed reference to a DBI::db object, not a DBI oject:

    $ perl -MDBI -e '$db = DBI->connect("DBI:mysql:database=test;user=x", +"x", "x"); print "\$db is a ", ref $db, "\n"' $db is a DBI::db

    I just settle for a 'has-a' relationship (my object "has a" DBI thingy in it) and leave it at that, works fine. Oh, it might be a good idead to invoke the disconnect method in your DESTROY sub so you won't get those nasty little warnings when the object goes away.

Re: inheritance not working as expected
by pope (Friar) on Jul 03, 2001 at 20:02 UTC
    When subclassing DBI, say into YourPackage package, you must also subclass DBI::db and DBI::st into YourPackage::db and YourPackage::st, respectively.
    Take a look at t/subclass.t included in DBI distribution as a working example on this.
Re: inheritance not working as expected
by bart (Canon) on Mar 03, 2011 at 12:25 UTC
    Since the database handle is a DBI::db object instead of a DBI object, your class is inheriting from the wrong class.

    Adjust your @ISA accordingly.

      bart:

      Heh, I figure by now he's already fixed the problem, or given up!

      ...roboticus

      When your only tool is a hammer, all problems look like your thumb.

        bart's wisdom isn't just for the OP.