PHP OOP Class Composition Tutorial

In this tutorial we learn how to instantiate a class inside another class in PHP to create loosely coupled applications.

We also cover the pros and cons of composition, and why we should favor composition over inheritance.

What is class composition?

Composition is another type of relationship between classes which allows one class to contain another. Where inheritance can be thought of as a Is-A relationship, composition can be thought of as a Has-A relationship. For example, a car has an engine.

Just like inheritance, composition allows for code reuse. Composition is more flexible and is a means to designing loosely coupled applications.

We may have a logging class that’s responsible for only logging to a text file. This class can then be used by any other class in our application to log anything.

How to associate classes through composition

To create an association between classes, we instantiate a new class object inside the constructor of the class we want to use it.

Syntax:
class Class1 {

    var $attributeName;

    function methodName() {}

}

class Class2 {

    var $obj1;

    function __construct() {
        $this->obj1 = new Class1();
    }

    $this->obj1->attributeName;
    $this->obj1->methodName();

}

When accessing the object inside another class, we should remember to reference the calling object (Class2) with $this.

Example:
<?php

class Logger {

    function log($message) {
        echo $message . "<br>";
    }

}

class DataMigrator {

    var $logger1;

    function __construct() {
        $this->logger1 = new Logger();
    }

    function migrate() {
        $this->logger1->log("Migrating. Please wait...");
    }
}

$dataMig = new DataMigrator();
$dataMig->migrate();

?>

In the example above, in the DataMigrator class, we instantiate the Logger object inside the constructor. This is similar to how we would construct a normal attribute except that we don’t require any input parameters.

Our migrate() method uses the log() method from the object instance. We access the object’s members with a second -> operator.

Composition over Inheritance

If composition only gives us indirect access, why use it?

The problem with inheritance is that it can be easily abused, which may lead to a large hierarchy of classes. A large hierarchy of classes is fragile, if we change a class at the top of the hierarchy, any class that depends on it is affected and may need to be changed as well.

As an example, let’s consider a class called Animal and some child classes that inherit from it.

Example:
<?php

class Animal {

    function eat() {
        echo "Eating...<br>";
    }

    function walk() {
        echo "Eating...<br>";
    }
}

class Dog extends Animal {}
class Cat extends Animal {}

?>

In the example above we have a Dog and a Cat that can both walk(). But, if we add a Fish, the hierarchy needs to change. We would need something like a Mammal class that inherits from Animal, and then we can inherit Dog and Cat from Mammal.

Favor composition

We can convert any inheritance relationship to composition. As an example, let’s consider that instead of Is-A animal, the child classes now Has-A animal.

Example:
<?php

class Animal {

    function eat() {
        echo "Eating...<br>";
    }
}

class Dog {}
class Cat {}
class Fish {}

?>

In the example above we forgot to give the Animal class a walk() method. If we were using inheritance, we would need to change the Animal class again. And, we still have the problem of the fish.

With composition, it’s as simple as adding two new classes.

Example:
<?php

class Animal {
    function eat() {
        echo "Eating...<br>";
    }
}

class Walkable {
    function walk() {
        echo "Walking...<br>";
    }
}

class Swimmable {
    function swim() {
        echo "Swimming...<br>";
    }
}

class Dog {}
class Cat {}
class Fish {}

?>

In the example above we added a class for any animal that can walk, and a class for any animal that can swim.

The Cat and Dog classes can implement both Walkable and Swimmable, and the Fish class can implement Swimmable.

If we wanted to add a bird, we could simply add a Flyable class, and the bird could implement Walkable, Swimmable and Flyable.

The application is now loosely coupled, as each class stands on its own and is not dependent on another class. Let’s look at a full example.

Example:
<?php

class Animal {
    function eat() {
        echo "Eating...<br>";
    }
}

class Walkable {
    function walk() {
        echo "Walking...<br>";
    }
}

class Swimmable {
    function swim() {
        echo "Swimming...<br>";
    }
}

class Flyable {
    function fly() {
        echo "Flying...<br>";
    }
}

class Fish {

    var $animal;
    var $swimmable;

    function __construct() {
        $this->animal = new Animal();
        $this->swimmable = new Swimmable();
    }
}

class Bird {

    var $animal;
    var $walkable;
    var $swimmable;
    var $flyable;

    function __construct() {
        $this->animal = new Animal();
        $this->walkable = new Walkable();
        $this->swimmable = new Swimmable();
        $this->flyable = new Flyable();
    }
}

echo "Nemo the fish's activities:<br>";
$nemo = new Fish();
$nemo->animal->eat();
$nemo->swimmable->swim();
echo "<br>";

echo "Tweety the bird's activities:<br>";
$tweety = new Bird();
$tweety->animal->eat();
$tweety->walkable->walk();
$tweety->swimmable->swim();
$tweety->flyable->fly();

?>

Inheritance & Composition pros and cons

Inheritance

  • Pros: Reusable code, easy to understand
  • Cons: Tightly coupled, can be abused, fragile

Composition

  • Pros: Reusable code, flexibility, loosely coupled
  • Cons: Harder to understand

We don’t mean that inheritance is a bad thing, it’s great and we will still need and use inheritance. Composition is just an alternative that we need to consider.

In most cases, we use both inheritance and composition throughout the application. We’ll learn more about composition with interfaces in the Interfaces tutorial lesson.

Summary: Points to remember

  • Composition is a relationship between classes that allows one class to contain another. Composition should typically be favored above inheritance, as it’s more flexible.
  • Composition allows for a more loosely coupled structure that avoids a fragile hierarchy of classes.
  • Composition is a Has-A relationship. A car has a steering wheel.