jeudi 27 juillet 2017

Dynamically instantiating classes using the Decorator pattern in PHP

Typically, when working with the decorator pattern, I usually instantiate the classes directly, one within the other:

abstract class Handler
{
    public function __construct(Handler $handler = null)
    {
        $this->handler = $handler;
    }

    abstract public function handle();
}

class FirstHandler extends Handler
{
    public function handle()
    {
        // Just calls the next guy in the chain. Obviously, this isn't doing anything, it's just for example sake.
        $this->handler->handle();
    }
}

// ... and so on with the SecondHandler, ThirdHandler, FourthHandler

$chain = new FirstHandler(
    new SecondHandler(
        new ThirdHandler(
            new FourthHandler()
        )
    )
);

$chain->handle();

However, with the possibility of the chain growing to say, perhaps, 20 handlers, you can see that the code would begin to indent far too much and makes it difficult to read, especially if different handlers in the chain don't have names as simple as "FirstHandler", "SecondHandler", but overall, it just doesn't look good.

I am wondering if there is a way to dynamically instantiate the classes by placing them in an array, and iterating down the array and passing the n+1 element in the array as the constructor argument to the nth element in the array.

I had something kind of like this in mind:

$chain = null;

$links = [
    FirstHandler::class,
    SecondHandler::class,
    ThirdHandler::class,
    FourthHandler::class
];

foreach ($links as $index => $link) {
    $chain = new $link(new $links[$index + 1]());
}

You might be able to tell that the first problem is that $chain gets overridden on each call. The second problem is that even with the loop, I still have to pass each handler into the chain manually, and all that is really doing is creating the chain the original way four times, which is actually worse. And the third problem is that eventually I will get an out of bounds exception.

Is there a way to instantiate this chain dynamically as demonstrated in my intention (perhaps a recursive call of sorts) or am I doomed to do it the way I was doing it before?

Aucun commentaire:

Enregistrer un commentaire