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?