Published on

Instantiating an Abstract Class with Dependency Injection

Author

In my Laravel app, I wrote an abstract class that has a fair bit of stand-alone behaviour. I wanted to test this directly instead of via the implementations.

PHP has anonymous classes, so instantiating it isn’t very tricky to do in a unit test. But the constructor also has about a dozen dependencies its asking Laravel’s service container for, and I wanted [almost] all those to be injected for me.

Problem is, I don’t think PHP lets you create an anonymous class and assign it to a variable, without instantiating it at the same time.

Instead, I found a clever trick: I can implement my own constructor and use App::call() on parent::__construct.

new class extends WorkflowFromJsonRepository {
    public function __construct()
    {
        App::call(parent::__construct(...), [
            'someParamToStub' => $stubbedThing,
        ]);
    }
};

If you need to pass stubs in, you can pick and choose by passing them in the second call() parameter. Ya’know, standard Laravel stuff at that point.

I am not sure if this trick would works on anything below PHP 8.1. The syntax with the three dots — parent::__construct(...) — is the new first-class callable feature. I’m not sure if you can get a handle on that using the older array-based syntax?