Object-oriented design advice with PHP

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

Post Reply
JobHoppingOrg
Forum Newbie
Posts: 1
Joined: Mon Feb 15, 2010 4:59 pm

Object-oriented design advice with PHP

Post by JobHoppingOrg »

I have several PHP Objects (Classes) that are closely tied to database records, such as Accounts, Profiles and the like. As a rule, I've been using methods in the classes, such as the constructor, to load and commit the data to the database.

So, for example:

$Account = new Account ( $databaseparms , $key );

This loads a new Account record using $databaseparms for mysqli and by searching for primary key $key.

I pass$databaseparms to the constructor, because they aren't saved with the Class definition. But maybe it would be better design to save them, or to have them inherited from a parent Class' static members, e.g. Account Extends DBObject? Not sure which is more elegant and simple design. Actually, I just thought of that second idea while writing this. :-)

What do you think?

Also, when I load a dependent class, such as the user's inbox, I might do one of:

$Inbox = new Inbox ( $databaseparms, $Account) // let the code find the key

OR

$Inbox = new Inbox ( $databaseparms, $Account->getKey() ) // call out the key explicity.

Again, it's a slightly different question of the same type. Should the Inbox class know how to access the Account key?

Should Inbox be a member of Account, and then it can be accessed as?:

$Account.Inbox.getMessages();

I hope those questions make sense. I am a bit new to OO programming,but it sure beats procedural from a design perspective! :-)

Thanks!
User avatar
Darhazer
DevNet Resident
Posts: 1011
Joined: Thu May 14, 2009 3:00 pm
Location: HellCity, Bulgaria

Re: Object-oriented design advice with PHP

Post by Darhazer »

First, I would separate low-level database access (including the DB connection) from the data classes. So instead of passing database access to each class, each class uses the DB abstraction layer to query the database.

The

Code: Select all

$Inbox = new Inbox ( $databaseparms, $Account->getKey() ) // call out the key explicity.
is the better approach imho. Decouple classes as much as you can. This means that your class should now know anything about the other one, unless it's really necessary or decoupling is rather complicated and the value is small.

Should be inbox a member of account? Well, think of a situation where you can have inbox without account. If you can come up with one, definitely inbox should not be part of the account.

Still, the account object can return instance to it's inbox. The important thing is to keep away from back-references - if account can return it's inbox, the inbox should not know anything about the account it's belonging to. Neither that it belongs to an account object at all. It should be possible to have another object, let's say Company, which can also return an inbox. The company inbox, not the personal one of some employee. :)

Go read "Head first design patterns". They have easy to understand examples of what coupling is and why it's bad :)
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Re: Object-oriented design advice with PHP

Post by Jenk »

I can't see the harm in possibly using:

Code: Select all

$Indox = Inbox::ForAccount($databaseparams, $Account);

Code: Select all

class Inbox
{
  public static function ForAccount($db, $Account)
  {
     return new Inbox($db, $Account->getKey());
  }
 
  // snip ...
}
User avatar
Darhazer
DevNet Resident
Posts: 1011
Joined: Thu May 14, 2009 3:00 pm
Location: HellCity, Bulgaria

Re: Object-oriented design advice with PHP

Post by Darhazer »

Jenk wrote:I can't see the harm in possibly using:

Code: Select all

$Indox = Inbox::ForAccount($databaseparams, $Account);

Code: Select all

class Inbox
{
  public static function ForAccount($db, $Account)
  {
     return new Inbox($db, $Account->getKey());
  }
 
  // snip ...
}
I would prefer to keep this in an InboxService. Reason - keeping the Inbox class small and independent from other classes. although there's no tight coupling here, the account object is a parameter to the function, adding such functions will increase the code base of the class.
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Re: Object-oriented design advice with PHP

Post by Jenk »

Again I don't see the harm in that. So what if the code base increases? It's static after all. :)
User avatar
Darhazer
DevNet Resident
Posts: 1011
Joined: Thu May 14, 2009 3:00 pm
Location: HellCity, Bulgaria

Re: Object-oriented design advice with PHP

Post by Darhazer »

Jenk wrote:Again I don't see the harm in that. So what if the code base increases? It's static after all. :)
And what's good with the static? Before version 5.3 you can go into big troubles with static calls. If you ever decide to call another static with self::ForAccount() you will find that you can subclass and predefine the ForAccount method.

Keep your objects relatively small, your methods short, and your classes decoupled from the rest of the code.
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Re: Object-oriented design advice with PHP

Post by Jenk »

Where have I used self:: ?!

Why create an entire class just for one method?!
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Re: Object-oriented design advice with PHP

Post by josh »

Personally I recommend separating out database code from business logic.

Code: Select all

 
// business logic
$account = new Account();
$account  = new Account( array( 'id' => 1 ) );
$account->setBalance( 100 );
$account->getBalance();
 
// persistence
$accountMapper = new AccountMapper;
$account = $accountMapper->load( 1 ); // persistence logic
$account->setBalance( 200 ); // business logic
$accountMapper->save( $account ); // business logic
 
Now you can be sure you have an application that works from say.... data coming in from a web service API, as well as the database. Differ "mappers" can be used for different persistence systems (Mysql, Postrelsql, flat file, xml, amazon SAN storage, object database, couch DB, whatever)

Most importantly though you can use your code with NO persistence framework present.
Post Reply