in reply to object method question

"How do I get that 'dbq' method into that _dbh object? So the client code could do: $dbh = $foo->get_dbh; $dbh->dbq( "blah blah whatever" );"

I can feel that you are a little bit confused. The first thing you need to do before you get into the coding, let's get your design clear.

So you want a class that wraps the basic database operations, which is fine. We got the mission statement, now let's look at the details of the class.

First we want a property holds the handler (or the connection), so that we can reuse that connection when we need it, and you got that - $self->{'_dbh'}, nice and clean.

Now you want three methods, 1) to initialize or set up the connection; 2) a getter to return the handler; and 3) a method to execute SQL queriES. Now the third one started to introduce soem sort of confusion to yourself. The way you used the mthod shows that.

Here is the confusion: on one hand, the dbq method knows the handler as it is part of this class we are working on, and uses the handler; On the other hand, when you call it, you used it in a way as if it is a method belong to a different class - a second class that wraps the handler.

The correct way of using your methods is (assume that your class is called DB):

my $db = DB->new(); $db->_setup_dbh($dsn, $user, $passwd); $db->dbq("whateverquery");

Now you probably want to consider other things like: 1) let the new() method call _setup_dbh; 2) let the dbq method return the query result, not the statement. Otherwise your class doesn't fully wrap the database operations, as the classes that use your class will need to know how to get result from a prepared statement. 3) the getter is not really needed. If all DB operations are wrapped inside, why does the outside world need the knowledge of this handler?

Replies are listed 'Best First'.
Re^2: object method question
by Zarathustra (Beadle) on Oct 11, 2005 at 06:42 UTC
    > I can feel that you are a little bit confused. >

    This exact sort of thing is a breeze in ruby.

    I say that with good humor!

    Unfortunately it's difficult to summarize precisely why I need to do what I'm trying to do here - the best I can do is explain _what_ I need...: It's important for me to be able to inject a custom method ( "dbq" ) into an object of an external class ( "DBI" ) which has been instantiated as an attribute ( "_dbh" ) of a custom base class ( "Foo" ). How do I do so?

    That is what I would like to do - if possible.

    >$db->dbq("whateverquery");

    That's fine for client code that directly instantiates an object of the class in question ( "Foo.pm", "DB.pm", whatever ).

    One may rightly ask: "So why not just pass the '$foo'/'$db' object itself to those legacy modules?"

    Because the "$db"/"$foo" class is much, much more than a simple, specialized/dedicated piece of functionality, such as your example. Passing a large object with a bunch of unrelated methods/attributes to another object that simply wants access to one specific method is serious, ugly overkill which I'm hoping to avoid - the very sort of thing why it's all being refactored/rewritten in the first place. In other words, I'm trying to trick the old code into just using the new stuff without a care or any suspicion that something has changed.

    I'm working with a semi-largish codebase, alot of which relies on receiving an object w/ a particular method, "dbq" in this instance. We're talking some 140+ perl scripts and shoddy modules that all rely on using/recieving this old '$dbh->dbq' thing.

    I've done some major refactoring and have written some decent oop libraries to replace the existing mess with something more sane; however we simply don't have the time to re-write/re-factor every one of those 140+ scripts/modules at the moment.

    Thanks for your time, it's difficult to communicate/discuss the nature of the problem without way too much verbosity and code!

      It's also a breeze in Perl, the other posters are simply questioning whether it is wise to go adding methods to a package that is outside your control.

      If you really want to do this, and you are smart about it (eg. your method only calls the publicly documented DBI methods on itself) then you simply need to define a new method in the right package space.

      For example, if you wanted to have a method that returned the most recent database error in all uppercase (to make sure it is heard loud and clear!), you could include this fragment in your code somewhere:

      { package DBI; sub err_loud { my $self = shift; return uc( $self->err() ); } }
      What the surrounding curly braces do is define a scopeso that the package pragma only applies within that scope. The sub/method err_loud thus becomes DBI::err_loud and will be found when perl tries to resolve the method call $dbh->err_loud()

      Perl trusts you not to shoot yourself in the foot, so you want to be really sure that this is what you want to do. As other posters have said, it would be more conventional to make a subclass.