How implement composition in php

profport picture profport · Sep 1, 2016 · Viewed 12.3k times · Source

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?

Answer

tereško picture tereško · Sep 2, 2016

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.