Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Object Oriented Perl - Help Getting Started 3

Status
Not open for further replies.

andycruce

Programmer
Jun 25, 2002
11
US
I have an application that I essentially hacked together that uses a flat file database to implement an addressbook and some other features. It works fine but I have decided to use this as an opportunity to learn DBI and OOP.

I have gotten DBI to work using mysql so at least I know how to create, read, write, update, modify a database useing SQL.

I was going to try to define a class in the OO sense that contained that data base. In doing this I've read the first part of Conway's Object Oriented Perl book and kind of understand the OOP concept. The problem I am having is "getting started". Here's my problem.

Is the class the individual records in the data base or the database itself. In the OOP examples a new object is created by the constructor and passed back to the user as a referent to a blessed anonomous hash. This seems to imply that the objects are stored as anonomous hashs rather than items in a database. I'm confused as to how to handle this. I obviously can't bless the database because that makes no sense.

From a proceedural point of view it's easy for me to figure out. I'd just make routines to do the DBI stuff I need and return whatever I need in scaler, array or hash as appropriate. But I'd really like to try to do something Object Oriented to figure out how to use objects.

I'd appreciate any suggestions or any recommendations of where to go look for more into.

Thanks

Andy Cruce
 
Keep it simple.

A class is just a collection of subroutines and variables (OOP terminology calls these methods and properties).

In perl, "Class" and "package" are synonymous. If you are a good developer, a single file is a single package. Don't be intimidated by the term 'package'. I was at first, I was thinking that perl actually 'packaged' up the code and maybe compressed it somehow. Nope. It's simply creating a new namespace for your variables and subroutines. This is how perl implements "Classes". As I said earlier, a "Class" in OOP is a collection of subs and variables, separate from global subs and variables: In perl, this is what a package does.

Now, as far as your situation goes, your database is your database, and not to be confused with your "Class" or an object (instance) of that "Class". Here is some psuedo-code that could in be an address book class. Basically, it provides a clean interface to interface with your database.
Code:
#===== Start of code: AddressBook.pm ==========
package AddressBook;
use DBI;  # You won't have to include this in your
          # code that uses this module now, 
          # because it's in here.  It's convenient.


sub new {    # A typical constuctor method
             # with defaults

  my $class = shift;

  my %self = @_;  # create hash, use args passed
                  # to the constructor

  # defaults for database connection
  # change these values to make them useful
  $self{'DBhost'} = 'localhost';  
  $self{'DBuser'} = 'default user name';
  $self{'DBpass'} = 'default password';
  $self{'DBname'} = 'default name of database to connect to';
  
  # add more defaults as necessary
  
  # create connection to database  

  my $dsn = "DBI:mysql:${self{'DBname'}}:${self{'DBhost'}}";
 
 $self{'DatabaseHandle'} = DBI->connect($dsn,$self{'DBuser'},$self{'DBpass'}, {RaiseError => 1, PrintError => 0});

 

  return bless(\%self, $class);  # the magic line
}


sub GetPhoneByLastName {
  
  # usage:
  # $phonenumber = $AddressBookObject->GetPhoneByLastName('Smith');

  my $self = shift;  # object is ALWAYS first argument!
                     # Unless it's a class method.  
  
  die "Not a Class method!" unless ref $self;
                 
  my $LastName = shift;  # retrieves argument

  my $query = "SELECT phone FROM tablename WHERE lastname = '$LastName'";

  my $sth = $self->{DatabaseHandle}->prepare($query);

  $sth->execute();

  ($Number) = $sth->fetchrow_array();  # don't need a loop
                                       # we expect only 1 
                                       # value... right?
                                       # probably not. 
                                       # but this is just
                                       # an example.
  return $Number;
}

# Add more useful object methods (subroutines)

1;

#===================== END =========================
[code]
OK, this is a pretty lacking module, but it gets the point across - I hope.  It's not tested, so there may be a syntactic snafu somewhere.  But hopefully it helps on some level.  And by the way, it's formatted nicely on my screen, but I'm sure this forum will fubar it up.

Basically, assuming this module works, you could write a script that does your address book stuff with few lines:
[code]
#=================== START ==========
use AddressBook;

my $book = new AddressBook;

@lastnames = qw/wall christiansen matz conway/;

$\ = "\n";  # Easy way to add \n to all print's

print $book->GetPhoneByLastName($_) for @lastnames;
#=================== END =============

Have fun.

--jim

 
That was a great post, Coderifous. It helped me a lot as well in understanding perl's OOP. However, I still don't understand the point of doing that; it seems needlessly complicated. What benefits are there to writing the above instead of the (perhaps newbie-ish) procedural code that I would probably use?
 
I think I am begining to get it. The class has nothing to do with the data. In fact, unless I am using different data base interfaces, which I am not, the details of the class are not important. It's just that establishing the class sets up things so I can do an OOP like call. If I have something like

package DataBase::Stuff;
sub new{
my ($class) = @_;
bless {
almost anything in here
}, $class;
}

sub LocateRecord { stuff to locate record and return as
and array}
sub ReplaceRecord { take data and update record}
etc.
ect.

Then in the main program I do something like

my $database = DataBase::Stuff -> new ( what ever new wants);

then I can access the routines using:
@ReturnedArray = $database->LocateRecord(what ever locate record needs);

So in this simplified application the OOP nature of things doesn't really do much except give me a fancy way to make subroutine calls. The power would come if I had several different database interfaces that were captured in the object so I could use the same "main program" code by just changing the object.

I appologize for bothering you again but is this close to correct. Seems to hold together logically but I could easily be missing something.

Thanks

Andy Cruce

 
Krel:

Thanks for the positive remarks. In reponse to your question as to what benefits are there to writing the above code verses procedural code, I would have to say there isn't one. But that's only referring to the above code. That example is so basic, that you could achieve the desired result of code reusage with a 'library' of functions. Although, even in this small example, the ending interface with this reusable code is cleaner, cooler, and provides the ability to create many instances of AddressBook objects. (In case you had different databases or something). Something that wouldn't be as easy to do with a mere library of functions.

OOP really flexes it's muscles when modeling complex real world problems. Also if you are part of a large project developing in Perl, the OO style is almost mandatory - otherwise different developer's code would be more likely to clash.

Functional programming will always be more appropriate given certain circumstances, but the same is true for OOP. It can make your life much easier. I think back to a massive heap of code I wrote when I was learning perl which helped automate part of my job at the time. I didn't know POOP (Perl Object Oriented Programming) yet, and also I didn't know crap (couldn't resist). Thinking back on it after I learned how to do OOP in Perl, that code could have been so much smaller and smarter. Also, I would have been able to do some complicated things which were difficult for me to work out in my head without the benefit of OOP understanding. So in conclusion here, OOP is definitely worth learning, and YOU WILL LOVE/USE IT once you learn it. Of course, you'll still write regular functional code all the time too. Atleast I do.

Andy:

"By god man I think he's got it."

Almost your entire post was right on target. The part where you said:
Code:
bless {almost anything in here}, $class;
I have to caveat that with: {almost anything in here} needs to be a reference. You are always blessing a reference into a class. So it will normally look like:
Code:
bless \$scalar_ref;  # pretty uncommon
#OR
bless \@array_ref;   # still not used to often
#OR
bless \%hash_ref;    # most objects
                     # refer to hashes.
Your OOP code can be as powerful, smart, and convenient as you make it. One thing that you may want to look at (unless you already have) is the wantarray function.
You use it to determine the context of the currently executing subroutine:
Code:
($areaCode, $firstThree, $lastFour) = $book->GetPhoneByLastName('Smith');
  # could return ('123','555','4323')
@list = $book->GetPhoneByLastName('Smith');
  # also could return ('123','555','4323')
$scalar = $book->GetPhoneByLastName('Smith');
  # could return '123-555-4323';
The magic here is that the same method responded to the context within which it was called, by returning either a list of values, or a scalar value. This can make things convenient and facilitate the "Do what I mean"-ness of perl programmers.

In your subroutine(GetPhoneByLastName)you would just change:

return $phonenumber;

to

return split('-', $phonenumber) if wantarray;
return $phonenumber; # logical fall through

So I'm glad I could help, and by the way: It's never a bother. Sometimes we have time, and sometimes we don't. I just happened to have the time.

--jim
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top