How to bind objects to specific parameters (not types) in Laravel's service container

90 Views Asked by At

Context: From a Laravel service container, we can easily bind abstracts to concrete implementations, and variables to scalar types, using the following, respectively:

// Abstracts to concrete implementations
$this->app->when(Foo::class)->needs(Bar::class)->give(new FooBar);

// Variables to scalars
$this->app->when(Foo::class)->needs('$bar')->give('fooBar');

Problem: I want to bind concrete classes to specific constructor variables (so a combination of the two), but it won't let me:

$this->app->when(Foo::class)->needs('$bar')->give(new FooBar);

That just returns:

Illuminate \ Contracts \ Container \ BindingResolutionException
Target [FooBar] is not instantiable while building [Foo].

At least, when the constructor variable is typed to FooBar, not when it's mixed. But setting it to mixed is not acceptable to me.

// Doesn't work:
class Foo
{
    public function __construct(
        protected FooBar $foo,
    )
    {
    }
}

// Works:
class Foo
{
    public function __construct(
        protected mixed $foo,
    )
    {
    }
}

To be clear, the new FooBar I want to inject is dynamically resolved, so I can't just new Foo(new FooBar), and I need this to work for multiple constructor arguments of the same type (which are each bound to different implementations), along with other dependencies:

class Foo
{
    public function __construct(
        protected FooBar $primaryFoo, // e.g. new Foobar('green')
        protected FooBar $secondaryFoo, // e.g. new FooBar('blue')
        // ... Other dependencies
    )
    {
    }
}

I can't figure out what syntax to use and I can't find anything that points to this in the docs or in the foundation code. It doesn't seem like I can achieve this with bind() as that is meant for use with abstracts. Any ideas?

0

There are 0 best solutions below