Article

The PHP Anthology Volume 1, Chapter 2 - Object Oriented PHP

Page: 1 2 3 4 5 6 7 8 9 10 11

Spotting the Difference

The general “thought test” to spot whether object A aggregates or composes object B is to ask, “What happens if object A dies? Will object B still be alive?” If object B outlives the death of object A, object A is said to aggregate object B. But if object B dies when object A dies, then object A is said to compose object B.

In terms of practical development, knowing when to apply aggregation or composition is important.

Aggregation has the advantage of lower overhead, because a single object will be shared by many other objects. Certainly, aggregating your database connection class is a good idea; composing it with every object that wants to make a query may require you to have multiple connections to your database, which will quickly halt your application when your site attracts high levels of traffic.

Composition has the advantage of making classes easier to work with from the outside. The code that uses the class doesn’t have to worry about passing it the other objects it needs, which, in a complex application, can often become tricky and result in a design “work around.” Composition also has the advantage that you know exactly which class has access to the composed object. With aggregation, another object sharing the aggregated object may do something to its state that “breaks” the object as far as the other classes that use it are concerned.

Polymorphism

Another powerful aspect of object oriented programming is polymorphism—the ability of different classes to share an interface.

An interface is one or more methods that let you use a class for a particular purpose. For example, you could have two database connection classes—one for MySQL and one for PostgreSQL. As long as they both offered a query method, you could use them interchangeably for running queries on different databases. The query method is a simple interface that the two classes share.

The classes sharing the same interface are often inherited from a parent class that makes the common methods available. Again, this is best understood by example.

First, we define an abstract base class, Message, which provides the common method getMessage. Beneath the Message class, we define concrete classes, each of which creates a specific message.

The terms “abstract” and “concrete” refer to class usage, in particular, whether a class is intended to be used directly or not. An abstract class is one in which some functionality or structure is to be shared by all subclasses, but is not intended to be used directly; typically, it has one or more empty methods that don’t do anything useful. In other words, you’re not supposed to create objects from an abstract class. A concrete class is a subclass of the abstract class from which you can create objects. Some languages, like Java, provide support for abstract classes within the language syntax—something PHP 4 doesn’t offer. You can still use the concept of abstract classes when designing applications, though you might consider adding documentation to tell other developers working with the code that the class is abstract.

Example 2.24. 14.php (excerpt)

<?php          
class Message {          
 var $message;          
 function setMessage($message)          
 {          
   $this->message = $message;          
 }          
 function getMessage()          
 {          
   return $this->message;          
 }          
}          
class PoliteMessage extends Message {          
 function PoliteMessage()          
 {          
   $this->setMessage('How are you today?');          
 }          
}          
         
class TerseMessage extends Message {          
 function TerseMessage()          
 {          
   $this->setMessage('Howzit?');          
 }          
}          
         
class RudeMessage extends Message {          
 function RudeMessage()          
 {          
   $this->setMessage('You look like *%&* today!');          
 }          
}

Now, we define the MessageReader class, which takes an array of Message objects through its constructor.

Example 2.25. 14.php (excerpt)

class MessageReader {          
 var $messages;          
 function MessageReader(&$messages) {          
   $this->messages = &$messages;          
   $this->readMessages();          
 }          
 function readMessages() {          
   foreach ($this->messages as $message) {          
     echo $message->getMessage() . '<br />';          
   }          
 }          
}

The important thing to note here is that, as far as MessageReader is concerned, a “Message object” is any object that was instantiated from the Message class or one of its subclasses. Did you see how, inside the readMessages method, we call the getMessage method? This code will work on any object that has a getMessage method—including any subclass of Message.

Now, to prove the point, let’s create some Message objects using our three subclasses at random:

Example 2.26. 14.php (excerpt)

$classNames =          
 array('PoliteMessage', 'TerseMessage', 'RudeMessage');          
$messages = array();          
srand((float)microtime() * 1000000); // Prepares random shuffle          
for ($i = 0; $i < 10; $i++) {          
 shuffle($classNames);          
 $messages[] = new $classNames[0]();          
}          
$messageReader = new MessageReader($messages);          
?>

By creating the array $classNames and then repeatedly shuffling it, we can take the first element of the array and use it to create a new object:

 $messages[] = new $classNames[0]();

This is an example of a variable function. The expression $classNames[0] is evaluated to determine the name of the constructor (PoliteMessage, TerseMessage, or RudeMessage) to call.

Finally, the $messages array contains ten messages, randomly selected, and is passed to the constructor of MessageReader on instantiation.

Here’s a sample result:

You look like *%&* today!          
Howzit?          
How are you today?          
How are you today?          
How are you today?          
You look like *%&* today!          
How are you today?          
How are you today?          
Howzit?          
How are you today?

Each time we execute the script, the list is different.

Because all the concrete message classes share the same getMethod function (i.e. they implement the same interface), the MessageReader class is able to extract the data without knowing which particular type of message it’s dealing with. The ability for a group of related classes to work interchangeably is called polymorphism, and is illustrated in the UML diagram in Figure 2.4.

1264_polymorphism
Figure 2.4. Polymorphism

This aspect of object oriented programming can be very powerful once you realize its worth. You might have a collection of objects representing HTML tags, for example, each being a subclass of a parent HTMLTag class, from which they all inherit a render method. Another class that handles the rendering of a page could take a collection of HTMLTag objects and create the page by calling each object’s render method.

Further Reading

Look out for more chapters from The PHP Anthology on SitePoint in coming weeks! If you can't wait, download the sample chapters, or order your very own copy now!

If you liked this article, share the love:
Print-Friendly Version Suggest an Article

Rate This Article

  • 1
    Poor
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
    Great

Comment on This Article

Have something to say?

Post A Comment

You need to be a member of the SitePoint Forums to comment on this post. Sign Up

Already a member? Post using your SitePoint Forums account: