12

I want to implement next fragment of diagram, using PHP.

See composition example diagram below:

enter image description here

We can implement composition in Java using inner classes.

But there is no analog of "inner class" in PHP. Of course, there are traits. But we can use it in more than one class.

I've implemented composition like this:

class Head {
    private static $instance = NULL;

    private function __construct(){}

    public static function getInstance() {
        $traces = debug_backtrace();
        if (strcmp($traces[1]['class'], 'Human')) {
            echo "<br>Only human has head"; // Exception can be thrown here
            return NULL;
        }
        if (!static::$instance) static::$instance = new self();
        return static::$instance;
    }

    public function __toString() {
        return 'Head';
    }
}

class Human {
    private $head;

    public function __construct() {
        $this->head = Head::getInstance();
    }

    public function __toString() {
        return 'I have ' . $this->head;
    }
}

class Plant {
    private $head;

    public function __construct() {
        $this->head = Head::getInstance();
    }
}

$human = new Human();
echo $human;

$superman = new Plant();

Is it right to do so?

Is there better way to implement composition relationship in PHP?

SaidbakR
  • 13,303
  • 20
  • 101
  • 195
profport
  • 131
  • 1
  • 1
  • 7
  • Paste your code in your question next time. Furthermore your code illustrates simple composition with a singleton class, what's the workaround and workaround for which problem? – dbf Sep 02 '16 at 07:57
  • Added code in question. "Workaround" because maybe there's better way to do it :) More native for PHP like inner classes in Java. – profport Sep 02 '16 at 12:20
  • where did you read that composition is about inner classes? – Wes Sep 02 '16 at 18:44
  • For example [here](https://habrahabr.ru/post/150041/) . Because in this situation we can prevent child class Head from instantiating outside parent class Human. It's not neccessary always. But can be useful sometimes. – profport Sep 04 '16 at 15:28
  • 1
    @profport And we all read Russian ... ;) – dbf Sep 04 '16 at 22:06
  • @dbf oh, how times have changed - today everyone on the internet is a russian bot :D – tereško Jul 12 '18 at 09:37
  • 2
    @tereško 2 years later, you just literally predicted the future! :D – dbf Jul 14 '20 at 23:29

2 Answers2

38

It looks like you are really confused about what "composition" is in OOP.

Composition is an association between two classes, where , for an instance of first class to be instantiated, it is mandatory to provide it with second class. In you particular diagram for Human to exists, it requires a Head. In code it would be:

class Head {
}

class Human {
    private $head;
    public function __construct(Head $head) {
       $this->head = $head;
    }
}

$bob = new Human(new Head);

And that's it. No debug_backtrace() and no singleton anti-pattern required. And, btw, this would look almost exactly the same in Java too, even with the option to have inner classes.

As for your posted code. This would be wrong:

if (strcmp($traces[1]['class'], 'Human')) {
    echo "<br>Only human has head"; // Exception can be thrown here
    return NULL;
}

The diagram did not say that only humans have a head. Only that human must have a head to be instantiated. You can also have $skipper = new Dog(new Head);, which would be perfectly fine.

DevWL
  • 17,345
  • 6
  • 90
  • 86
tereško
  • 58,060
  • 25
  • 98
  • 150
  • Thanks @tereško, I was really confused. I thought that composition means: **only** Human has Head. Maybe your code closer to aggregation. In composition, as I know, we should instantiate some class **inside** another class. E.g. public function __construct() { $this->head = new Head(); } – profport Sep 04 '16 at 15:21
  • Of course in the most situations it can be useful to re-use Head class in other classes. But is it possible to restrict composition in UML diagram? I.e. **only** Human has Head? It can be neccessary sometimes. – profport Sep 04 '16 at 15:24
  • 1
    No, it's not possible to restrict, but you have require for a `Human` to have `HumanHead` which extends `Head`. I would also caution against trying to fit OOP in some "real world" context. Programming does not deal with real world but with abstractions. – tereško Sep 04 '16 at 16:12
  • but this code example show relationship between `Head` and `Human` is just like association as shown below link
    https://www.thoughtco.com/association-2034002
    – Susantha7 Aug 24 '17 at 07:08
  • @Susantha7 no. The example show that `Head` is a **mandatory dependency** in the constructor. In that example of yours, the `Bomber` instances are added **only** after the instance i already created. That is the difference between composition and association. – tereško Sep 14 '17 at 10:18
  • what if bob, later on needs new legs? how would that look? – klewis Apr 24 '19 at 19:34
  • @klewis `$bob = new Human(new Head, new Legs);`, or you would change his legs with a method providing new legs. – Jimbo Dec 27 '21 at 13:05
6

Composition over inheritance.

Basically composition is a stronger form of aggregation. We could say that relationship between body and head is composition because we can not live without head but relationship between body and a hand is aggregation because we could lose our hand but we can stay alive. There are also weaker relations like direct association and temporary association.

Dependency injection however is just a pattern in which we create those associations (by injecting one class in to another).

In most cases you could recognized composition relationship by constructor which inject another object and assign it to its property and life cycle of object ends and start in the same moment.

Other than that from technical point of view there is not much difference between implementation of each association. It is mostly matter of relation definition rather than implementation.

Composition relation is often used to overwrite/change or enhance injected object class behavior. Don't get too excited or worried about composition. In most cases, the advantages versus inheritance are small, and are most enjoyed by third-party library creators, who use composition to add extra flexibility to their libraries.

Inheriting from parent class and overloading/adding methods gives us similar functionality, but with composition we get more flexibility. For example if our constructor accept object that inherit from Head interface we can use HumanHead class if it extends Head interface but we could also use our class to enhance other creatures which extends from same interface like DogHead or DuckHead...

This is perhaps not the best example but it shows the basic concept.

Be sure to check this [Aggregation vs Composition vs Association vs Direct Association] and this [Association-Aggregation-Composition-Dependency].

Antoine
  • 800
  • 3
  • 14
  • 29
DevWL
  • 17,345
  • 6
  • 90
  • 86