← Home

A php way to simple class aggregation

There are basically two ways to add behaviour to an existing class: Inheritance and Composition.

Inheritance has a couple of drawbacks: It leads to bloated class trees, making it difficult to change things later on. It tightly couples the derived class with the base class, so that we can't use the behaviour that is added by the derived class anywhere else. It violates the principle of having one class for one responsibility by packing more and more behaviour into one single class. And so on.

Composition on the other hand is a nice thing, when it comes to the need of having cleanly separated classes that are responsible for one task and nothing else. But Composition often means adding large numbers of methods to the interface of the adapting class or otherwise expose the adapted class instance to the world. So the class "composing" our neat, separated "composite" classes together won't be clean at all.

For some examples and code have a look at Javaworld's "Inheritance versus composition: Which one should you choose?". On page two there are the two classes Fruit and Apple:

Apple inheritance

class Fruit {
   public funciton peel() {
      echo "Peeling is appealing.";
   }
}
class Apple extends Fruit { }
$apple = new Apple(); $apple->peel();

Apple composition

class Fruit {
   public function peel() {
      echo "Peeling is appealing.";
      }
   }
}
class Apple {
   private $fruit;
   public function __construct() {
      $this->fruit = new Fruit()
   }
   public function peel() {
      return fruit->peel();
   }
}
$apple = new Apple();
$apple->peel();

As is shown in the article at Javaworld, the composition way is more flexible in plugging additional behaviour into the class Apple later on. That's cool. But the class Apple has to add it's own peel() method.

Of course, our real-world classes aren't that simple. Consider what happens when a class adapts - say - three composites and has to expose 10 methods from each of them: We would not only have to write these 30 methods, but 30 additional methods to use them in the adapting class. Composition leads to less compact code, thus introducing additional sources of error.

So, should we better rely on inheritance by default? Often there's no way of using inheritance in a persuasive manner at all. Let's think of a description like the following:

The "real" world

"In our framework a 'component' is defined as a piece of software that 1.) holds and manages properties that can be added, removed and changed from outside and 2.) has a lifecycle (with the stages init, execute, exit), that can be run through. A component can 3.) be defined and populated by a 'component definition', that's being provided by an xml file."

(Not exactly the same, but in essence something similar, you'll find in the award-winning and indeed very cool php5 Prado Framework's TComponent and TControl classes.)

As you can see, according to this definition there are three completely different responsibilities mixed into one single class: Managing properties has nothing to do with defining and entering lifecycle stages. A Lifecycle has nothing to do with dynamically populating an object from an xml definition. And the latest task has nothing to do with the first.

Now, should we build a ...

class PropertyManager
class LivingPropertyManager extends PropertyManager
class Component extends LivingPropertyManager

... class tree (adding the component definition stuff to the class without naming it as class name)?

Or better a ...

class Lifecycle
class PropertyLifecycle extends Lifecycle
class Component extends PropertyLifecycle

... class tree?

Obviously that's all crap. So, we'll create one single, huge class throwing all the propertymanaging, lifecycle and component definition stuff into it. ;-)

class="storytitle">Doing it the php way

With php's magical __call() method and call_user_func_array(), there's a different way to achieve Composition of cleanly separated classes that maintain one single task and nothing else - without the drawback of writing new methods over and over again.

First, we'll implement the three tasks as separate classes. The PropertyManager will have two simple methods getProperty() and setProperty():

class PropertyManager {
   private $properties = array();
   pubic function getProperty($name) {
      if (isset($this->properties[$name])) {
         $value = $this->properties[$name]);
         echo "returning property $name: $value<br>";
         return $value;
      }
   }
   pubic function setProperty($name, $value) {
      echo "setting property $name to $value<br>";
      $this->properties[$name] = $value;
   }
}

For the Lifecycle we'll have a class with a single method for this example: run() starts the lifecycle:

class Lifecycle {
   private $stages = array('init', 'execute', 'exit');
   public function run() {
      foreach ($this->stages as $stage) {
         echo "entering lifecycle stage $name<br>";
      }
   }
}

The ComponentDefinition class' getDefinition method() will parse an xml string containing a simple definition. The populate() method will populate a Component from this definition:

class ComponentDefinition {
   public function getDefinition() {
      echo "parsing component definition xml string<br>";
      $xml =
         '<component>' .
         '  <property name="foo" value="bar">' .
         '</component>';
      return simplexml_load_string($xml);
   }
   public function populate(Component $component) {
      echo "populating the component from xml definition<br>";
      $definition = $this->getDefinition();
      $name = (string) $definition->property->name;
      $value = (string) $definition->property->value;
      $component->setProperty($name, $value);
   }
}

Now, we can plug these things together in a Component class that implements all the behaviour required by our class description above.

class Component {
   private $aggregatees = array();
   public function __construct() {
      $this->aggregate(new PropertyManager());
      $this->aggregate(new Lifecycle());
      $this->aggregate(new ComponentDefinition());
      $this->populate($this);
   }
   private function aggregate($aggregatee) {
      echo "aggregating " . get_class($aggregatee) . "<br>";
      $this->aggregatees[] = $aggregatee;
   }
   private function __call($method, $args) {
      foreach ($this->aggregatees as $aggr) {
         if (method_exists($aggr, $method) {
            call_user_func_array(array($aggr, $method), $args);
         }
      }
   }
}

As you can see there's no need to write any additional methods to access the aggregated class instances (like in javaworld's Apple/Fruit example). But we save the compositions advantage and have all three tasks separated from each other in a reusable manner (thus, we could plug the PropertyManager or Lifecycle into another class without modifying them).

To test the example classes:

$component = new Component();
$component->run();
This will return:
aggregating PropertyManager
aggregating Lifecycle
aggregating ComponentDefinition
returning component definition xml string
populating the component from xml definition
entering lifecycle stage init
entering lifecycle stage execute
entering lifecycle stage exit

class="storytitle">Where to go from here ...

Blog articles shouldn't be too long, so we won't work this out much further. In the real world we would want to access the Component class from the aggregated classes.

As a sharp reader you'll have noticed the line $this->populate($this) (which is inelegant, to say the least) in the Component's constructor and the fact that there's no possibility to access the Component from within the Lifecycles run() method.

So, we would add a reference to the Component instance in the Property Manager's, Lifecycle's, and ComponentDefinition's constructor:

class Lifecycle {
   private $aggregator = null;
   public __constructor($aggregator) {
      $this->aggregator = $aggregator;
   }
   public run() {
      foreach ($this->stages as $stage) {
         // do something with the Component's instance
         $this->enterStage($this->aggregator);
      }
   }
}
... and initalize it from the Components constructor by:

   $this->aggregate(new Lifecycle($this));

Furthermore, for convenience we'll want to access the Component's (and all its aggregated objects) methods from within any aggregated object instance. So we add a __call() method to the Propertymanager, Lifecycle and Component Definition:

class ComponentDefinition {
   private $aggregator = null;
   public __constructor($aggregator) {
     $this->aggregator = $aggregator;
   }
   //the parameter Component $component can be omitted now
   public function populate() {
      $definition = $this->getDefinition();
      $name = (string) $definition->property->name;
      $value = (string) $definition->property->value;
      $this->setProperty($name, $value);
   }
   public function __call($method, $args) {
      call_user_func_array(array($this->aggregator, $method),
         $args);
   }
}

class="storytitle">What about the naming?

To be honest I have to say that I'm really not sure about the naming of this pattern as an Aggregator (any advice on that would be very appreciated).

In fact, there's an experimental php extension called "Object Aggregation/ Composition Functions". This extension provides a method aggregate() doing exactly the same - or at least it should do so, according to the docs. Maybe the existence of a php method with the same name can be taken as a hint that the naming can't be completely wrong. :-?

The Javaworld article mentioned above talks about "composition" here. Having googled for "composition aggregation" and found some definitions and discussions (like here and here) I came to the opinion that aggregation is the more appriopriate term.

Sebastian Bergmann on the other hand calls the same thing a "delegate": After having sketched down this article, I found the article: Introduction to Interceptors I: Implementing Delegation from Sebastian Bergmann on Zend, published on August 12, 2003 ... :-)

blog comments powered by Disqus