Reading about laravel bindings ,I understand $this->app->bind
, $this->app->singleton
and $this->app->instance
because they are almost the same.
But $this->app->when
is a little bit tricky for me.
In laravel example
$this->app->when('App\Http\Controllers\UserController')
->needs('$variableName')
->give($value);
In my understanding it injects some primitive value and the App\Http\Controllers\UserController
is the alias of the object that will be binded.But where is the object?
Can anyone explain? Thank you for your help.
Contextual binding does not work on variable names, but on types. It is used to provide different implementations for interfaces to consuming classes or functions, depending on the context. In fact, you can actually read the method calls and it does exactly what you'd expect. To elaborate on this, I'll take the example of the documentation and adapt it slightly:
$this->app->when(Worker::class)
->needs(Money::class)
->give(function () {
return new Dollar();
});
$this->app->when(Boss::class)
->needs(Money::class)
->give(function () {
return new Cheque();
});
In this example, Money
is an interface and Dollar
as well as Cheque
are implementations of the interface. The example literally means that if you typehint Money
on a Worker
class, it will resolve to an instance of Dollar
while it will resolve to Cheque
on a Boss
class. To illustrate, here the implementations and the results:
interface Money
{
public function getAmount();
}
class Dollar implements Money
{
public function getAmount()
{
return 1;
}
}
class Cheque implements Money
{
public function getAmount()
{
return 100000;
}
}
And now we typehint the Money
interface to see what we'll get:
class Worker
{
public function __construct(Money $money)
{
echo $money->getAmount(); // prints '1'
}
}
class Boss
{
public function __construct(Money $money)
{
echo $money->getAmount(); // prints '100000'
}
}
It means that if a class of UserController
is instantiated and it needs a variable with the name $variableName
Larvel will automatically resolve this variable with the given value and you don't have to provide it.
For example:
$value = "Sven"
$this->app->when('App\Http\Controllers\UserController')
->needs('$userName')
->give($value);
This would insert the value 'Sven' into the UserController whenever it needs the variable with the name $userName
In other words, if you had a function like public function __construct(Request $request)
Laravel knows what to insert because it knows that a Request
object is expected. When you use a function like public function __construct($name)
Laravel has no clue what to insert here, essentially you tell Laravel how to resolve this variable with the bindings.
This is an example of primitive binding , for Contextual binding see the answer of @Namoshek
In case anyone finds this thread, trying to achieve contextual binding on an app()->make() or similar situation:
use Closure;
use Illuminate\Container\Container;
class FooBar {
public function doSomething(): void
{
//...do your thing
$this->getFooObject();
}
private function getFooObject(): FooAbstract
{
$class = FooAbstract::class;
$buildStack = static::class;
app()->beforeResolving(
$class,
Closure::bind(
function () use ($buildStack) {
$this->buildStack[] = $buildStack;
},
app(),
Container::class,
)
);
return app($class);
}
}
In the above example laravel's app container is bind as $this
to this closure. Since the buildStack
property, that's used to identify the object that "needs" the object that is being created, is protected, we have access to it, and we can add the classname to the stack.
for example: if $buildStack = Bar::class
; you can do the following
app()->when(FooBar::class)->needs(FooAbstract::class)->give(FooImplementation::class);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.