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

I've read the Simple Module Tutorial and realized that I probably don't need to use objects, modules will work for me. I still have one question that has been evading me: What's the best way to use objects in exported functions? I've got a main program that looks like this:
#!/usr/bin/perl -w use strict; use DBI; use Exported qw(:All); my $db_info = "dbi:mysql:database;host=localhost"; our $dbh = DBI->connect($db_info, 'username', 'password', { PrintError + => 0 }) or die("Couldn't connect to database\n"); print "info: " , getdb() , "\n";
And the Exported.pm module looks like this:
#!/usr/bin/perl -w package Exported; use strict; use Exporter; use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); $VERSION = 1.00; @ISA = qw(Exporter); @EXPORT = (); # no default exports @EXPORT_OK = qw(&getdb); %EXPORT_TAGS = ( All => [qw(&getdb)] ); sub getdb { my $query = $main::dbh->selectrow_hashref("SELECT something FROM a +_table"); return $query->{'explanation'}; }
See that $main::dbh->selectrow_hashref()? I don't like it at all. Is there a better way to access the $dbh object from Exported.pm?

Replies are listed 'Best First'.
Re: Using objects in exported functions
by chromatic (Archbishop) on May 31, 2004 at 02:44 UTC

    Pass it as an argument to the function.

    print "info: " , getdb( $dbh ) , "\n"; sub getdb { my $dbh = shift; my $query = $dbh->selectrow_hashref("SELECT something FROM a_table +"); return $query->{'explanation'}; }
      I should have said beyond passing it everywhere. Obviously the project I'm trying to apply this to is much bigger than the example I posted, and there are several of these objects that get used in many places. I'd really rather not have to pass them around everywhere.

      I'm hoping there is some feature I'm unaware of that will allow me to use these things outside of their namespace easily. If not, then there isn't a better way to do it and I'm happy enough.

        You only have three options: pass it around, store it in objects that need it, or make it globally accessible. You can do the latter with a bit of encapsulation though:

        my $dbh = DBI->connect($db_info, 'username', 'password', { PrintError => 0 } ) or die("Couldn't connect to database\n"); sub get_handle { my $dbh; } print "info: " , getdb() , "\n";

        Then you can call main::get_handle() from anywhere, instead of accessing a global variable. It's effectively the same, though it's a little nicer with the encapsulation.

        If you don't want to pass it everywhere, you have at least two options: either set it as a module-wide parameter, or use objects and store it within each instance of the object. The first results in module code that looks like this:

        This will work, but it means that this module can only ever access one database at a time (let alone the bad things that would happen in the presence of threads.) My personal preference is to use an object to encapsulate the necessary context:

        This allows you to have two MyQuery objects "alive" at once. Which may or may not matter, but generally if you want to tie specific data (in this case, the $dbh) and some operations together, then consider using an object.

        p.s. If you just want a shorthand way for functions in package Exported to refer to $main::dbh as though it were in its own namespace, then you might be able to get by with typeglob aliasing:

        The only thing to watch out for here is that $main::dbh has to be a global name (declared with our), not a lexical variable (don't use my).

Re: Using objects in exported functions
by Anomynous Monk (Scribe) on May 31, 2004 at 11:06 UTC
    Can you explain more what you don't like about it? You seem to want to be accessing a global from another package; code that explicitly says that ($main::dbh) would seem to me to be the way to go.

    But, if you really want, you could put package main; our $dbh; before the package Exported line; then simply $dbh will refer to the one in main.

    Or, at some miniscule risk of perl later trying to use the same name for some internal purpose, you could use a "punctuation variable" like ${^Dbh}. Such variables are always looked for in package main.