开发者

OOP Best Practices (specifically PHP)

I've been developing in PHP for a while now but only recently made the switch over to an OOP approach.

One question that keeps cropping up for me is 'how far' to go with the OOP stuff, specifically in terms of execution speed and memory resources etc.

For example, let's say I have 2 objects, User and Listing

Listings are always linked to a individual user. UserId is a property of Listing so I know which user it relates to. Once in a while, within a Listing method I need to access a single property of the related User.

As far as I can see (please advise if not) I have 3 options for how to accomplish this.

  1. Create a new user object and access the relevent propery via $user -> theProperty

  2. Make the required property a local property of Listing and populate this when Listing is initialised (e.g. via a sql join)

  3. Query the database directly to retrieve the property of User required via the user ID

It seems to me that options 1 & 2 obide by OOP rules more stringently, but have performance hits due to initialising a whole object simply to retrieve 1 property. Option 3 would be the least memory intensive but sidesteps OOP altogether.

In addition, in terms of populating objects at creation, most of my objects get most of their p开发者_如何学编程roperties populated via one 'fill' method shortly after being initialised (hence requiring only 1 DB query). Would this generally be considered best practise, or would it be more advisable to use individual methods to get these properties, populating as and when they are needed?

I realise there may not be "correct" answers to this, but could anyone give an advice on best ways to approach this situation?

Many thanks Nick


I definitely prefer option 1. Option 2 does not follow the idea behind OOP because user information is not part of your listing, so keep it in a separate object.

Keep the following rules in mind:

  1. Load an object without its relationships at once.
  2. If you need a related object load it at the time you need it according to rule 1

Many ORMs work this way, for example Doctrine ( http://www.doctrine-project.org ). It's called lazy loading.

When you need one property of an object you will find yourself loading a second property of that same object some lines further. In many cases you will find yourself doing numerous database queries within a complete script for just one object.


Option 1 is the prefered OOP way.

Alternatively, in php you could write a wrapper object which only contains the user_id and the properties you need.

And when a method is called or a other property is accessed you can load and initiate a real user object.

This can be achieved which the __get(), __set() and __call() methods.

That way you can optimize the query and memory usage of the Listing object while having access to all the OOP goodness from the user object, when needed.

Code should look something along the lines of:

class LazyObject {

  private 
    $propertySubset = array(),
    $realObject;


 function __call($method, $args) {
    if ($this->realObject === null) {
      $this->initRealObject();
    }
    return call_user_func_array(array($this->realObject, $method), $args);
  }

  // __get, __set and initRealObject implementation goes here

}

Caveats

  • You can use references: myMethod(&$ref) and $shortcut = &$object->prop wont work
  • You'll need to manually check if you filled the wrapper with enough properties. Not enough properties will result in allot of queries and the wrapper only slows thins down.
  • Usage of interfaces (like ArrayAccess) won't work unless you implement them in the lazyObject

PS.
This should be considered an optimalisation hack. So implement this only if the performance is becoming an issue;


Before you rush on option #1, I would recommend to remain that trying to apply a simple object model to data stored in a database may bring much complications.

Just read this in order to have an idea of what I'm telling: "Why did object oriented databases fail"

Has you say Nick , there is not a "correct" answer. But we can say this:

In an OOP ideal good practice, the $listing object should have $listing->user property that is a object representing the Listing's User. For better performance, this User object should not be instantiated as soon as $listing is instantiated. In the Java traditional coding, you would have a method ->getUser(). In PHP you can have this object instantiated as soon as you call for the ->user property.

But retrieving complete user information when you need only one property, this may cost much useless data flow. This is particularly true if your code intends to process a large number of Listing objects at a time.

If it's so, then you must move a way a little bit from the ideal object model in order to be closer to your business process. Then retrieving only the user property you need, that may be a good compromise. For example: $listing->getUserProp1(). If you may need other user properties in the future then you may change the method into $listing->getUserProprty('prop1').

But this option is good only if you need the User property sometimes. If in fact you need it quite each time you have a Listing object, then it's better you have the User property already initialized with other Listing properties. This is you option #2. It's seems to be a very good solution in you need data flow minimized and if you do not need other user information nearby the Listing object.


I believe you need to take a look to Data Transfer Objects design pattern:

  • http://en.wikipedia.org/wiki/Data_transfer_object

Views (pages) should receive data-transfer objects which mustn't be the same ones that your data-access layer work with.

With some parameterization, your business layer may return DTOs which have a specific set of one or more objects returned by data-access layer.

For example, if you want to list users, maybe you want to know their "group identifier", "user identifier" and "full name".

User group's identifier would come from some Group object, while user's identifier and full name would come from some User object, and finally, a UserDto object would have properties of User and Group objects that would be what some user interface view needs to show user listing.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜