2

Let's say that we have a Dog class and a Category class that dogs can be assigned to.

class Dog {
    function categories() {} // Return the categories of the dog.
}

class Category {
    function dogs() {} // Return the dogs under this category.
}

Dogs can have 'pet' and 'shepherd' categories. When assigned to 'pet' category, it's a 'pet dog' and the same goes for 'shepherd'.

Pet dogs and shepherd dogs have different attributes and functions. However, a dog can be both a 'pet dog' and a 'shepherd dog'.

I can imagine having different interfaces for 'pet dog' and 'shepherd dog', e.g.

interface Huggable {
    function hug();
}

interface Trainable {
    function train();
}

Ideally, when a dog is assigned to 'pet' category, it implements the Huggable interface, if it's assigned to 'shepherd' category, it implements the Trainable category.

Is it possible?

1
  • PHP doesn't allow you to mix classes dynamically. This might be a good use for traits Commented Sep 11, 2018 at 15:46

1 Answer 1

3

As I commented, it is not possible to implement this with PHP natively.

But you could implement something using decorators, for example.

A silly decorator approach:

You'd have your to-be-decorated class:

class Animal {

    protected $categories = [];

    public function getCategories() {
        return $this->categories;
    }

    public function addCategory( string $category ) {
        // we should check the animal doesn't already belong to this category
        $this->categories[] = $category;

    }
}

Your interfaces, Trainable and Huggable:

interface Trainable {

    function train();
}

interface Huggable {
    // see https://github.com/php-fig/fig-standards/blob/master/proposed/psr-8-hug/psr-8-hug.md
    function hug() : bool;
}

One decorator that implements Trainable, and adds the specific category to the decorated instance:

class PetDecorator extends Animal implements Trainable {


    public function __construct( Animal $animal ) {

        $this->categories = $animal->getCategories();
        $this->addCategory('pet');

    }

    public function train() {
        echo "I'm housebroken!\n";
    }
}

And another FluffyDecorator that implements Huggable

class FluffyDecorator extends Animal implements Huggable {

    public function __construct( Animal $animal ) {

        $this->categories = $animal->getCategories();
        $this->addCategory('loveBear');
    }

    public function hug( ) :bool {
        echo "Much hug!\n";
        return true;
    }
}

Finally, you'd use it thus:

$fido    = new Animal();
$fidoPet = new PetDecorator($fido);

$fidoPet->train();
// I'm housebroken!

print_r($fidoPet->getCategories());
/*
Array
(
    [0] => pet
)
*/

$fidoLove = new FluffyDecorator($fidoPet);
// Much hug!
$fidoLove->hug();

print_r($fidoLove->getCategories());
/*
 Array
(
    [0] => pet
    [1] => loveBear
)
 */

The many-to-many relationship between "Dogs" and "Categories" I leave up to you. That's a separate issue and could be handled in many different ways.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! I am recently new to oop and I understand the power and cleanliness of oop. This post helped me a bit to understand how extends work. Good work sir!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.