Laravel 绑定的用途和目的是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/49348681/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 17:31:54  来源:igfitidea点击:

What is a usage and purpose of Laravel's binding?

phplaravel

提问by Andrii H.

I cannot understand a point of Laravel's binding system. I know what does dependency injection mean. And it can work even without that weird "bindings", right? I saw in documentation, that binding can return a new object. Why and when I have to use that? Please, explain not very complicated, because I've read documentation and I could not understand the use and the purpose of that bindings. Thanks.

我无法理解 Laravel 绑定系统的一点。我知道依赖注入是什么意思。即使没有那种奇怪的“绑定”,它也可以工作,对吧?我在文档中看到,绑定可以返回一个新对象。为什么以及何时必须使用它?请解释不是很复杂,因为我已经阅读了文档,但我无法理解该绑定的用途和目的。谢谢。

回答by Risan Bagja Pradana

And it can work even without that weird "bindings", right?

即使没有那种奇怪的“绑定”,它也可以工作,对吧?

Not really. Sure it can work just fine if the required dependencies are simple to instantiate. Let's say you have this simple class Foostored in appdirectory:

并不真地。如果所需的依赖项易于实例化,它当然可以正常工作。假设您将这个简单的类Foo存储在app目录中:

<?php

namespace App;

class Foo
{
    public function hello()
    {
        return 'Hello World';
    }
}

You can type hinted this class without binding it first in the container. Laravel will still be able to resolve this class. Let's say you type-hinted it like this in the routes:

您可以键入hinted 此类,而无需先将其绑定到容器中。Laravel 仍然可以解析这个类。假设您在路由中这样输入提示:

Route::get('/foo', function (App\Foo $foo) {
    return $foo->hello(); // Hello World
});

We can even go further, let's say this Fooclass required another simple class Bar. Our Barclass looks like this:

我们甚至可以更进一步,假设这个Foo类需要另一个简单的类Bar。我们的Bar班级是这样的:

<?php

namespace App;

class Bar
{
    public function hello()
    {
        return 'bar';
    }
}

And our Fooclass looks like this now:

我们的Foo类现在看起来像这样:

<?php

namespace App;

class Foo
{
    public function __construct(Bar $bar)
    {
        $this->bar = $bar;
    }

    public function hello()
    {
        return $this->bar->hello();
    }
}

Will Laravel be able to resolve the type-hinted Fooclass now? YES! Laravel will still be able to resolve this Fooclass.

LaravelFoo现在能够解析类型提示类吗?是的!Laravel 仍然可以解析这个Foo类。

Now the issue will come in when our Fooclass needs slightly more complex dependencies that need to be configured. Imagine that our Fooclass simply need the name of our application. Sure you can simply use config('app.name')within the class's method, but imagine that this can be an HTTP client that requires a configuration array to instantiate.

现在,当我们的Foo类需要配置稍微复杂的依赖项时,问题就会出现。想象一下,我们的Foo类只需要应用程序的名称。当然,您可以简单地config('app.name')在类的方法中使用,但是想象一下,这可以是一个需要配置数组来实例化的 HTTP 客户端。

<?php

namespace App;

class Foo
{
    public function __construct($appName)
    {
        $this->appName = $appName;
    }

    public function hello()
    {
        return "Hello {$this->appName}";
    }
}

Will Laravel be able to solve this class now? NOPE. Service Containerto the rescue! You can teach Laravel how to resolve this Fooclass by binding it in service container. You can define the binding within the registermethod on app\Providers\AppServiceProvider.phpfile:

Laravel 现在能解决这个类了吗?不。服务容器来救援!你可以Foo通过在服务容器中绑定它来教 Laravel 如何解析这个类。您可以registerapp\Providers\AppServiceProvider.php文件中的方法中定义绑定:

public function register()
{
    $this->app->bind(\App\Foo::class, function ($app) {
        // Pass the application name
        return new \App\Foo($app->config['app.name']);
    });
}

And sometimes, you don't want multiple instances to be created. Like our Fooclass for instance, there's no need for multiple instances for this kind of class. In this case, we can bind it with singleton method.

有时,您不希望创建多个实例。就像我们的Foo类一样,这种类不需要多个实例。在这种情况下,我们可以使用单例方法绑定它。

$this->app->singleton(\App\Foo::class, function ($app) {
    return new \App\Foo($app->config['app.name']);
});

More Important Usage

更重要的用法

But the more important usage of this service container is that we can bind an interface to it's implementation. Let's say we have this PaymentProcessorInterfacewith paymethod:

但是这个服务容器更重要的用途是我们可以将一个接口绑定到它的实现。假设我们有这个PaymentProcessorInterfacewithpay方法:

<?php

namespace App;

interface PaymentProcessorInterface
{
    public function pay();
}

Then we have the implementation of this interface named StripeProcessor:

然后我们有这个接口的实现,名为StripeProcessor

<?php

namespace App;

class StripeProcessor implements PaymentProcessorInterface
{
    public function pay()
    {
        return 'pay with stripe';
    }
}

With service container, we can bind the PaymentProcessorInterfaceto StripeProcessorclass:

使用服务容器,我们可以绑定PaymentProcessorInterfacetoStripeProcessor类:

$this->app->bind(\App\PaymentProcessorInterface::class, function () {
    return new \App\StripeProcessor();
});

We can then type-hinted PaymentProcessorInterfacewithin our code:

然后我们可以PaymentProcessorInterface在我们的代码中进行类型提示:

Route::get('/pay', function (App\PaymentProcessorInterface $paymentProcessor) {
    return $paymentProcessor->pay(); // pay with stripe
});

This way we can easily swap the PaymentProcessorInterfaceimplementation. Let's say we want to change the payment processor to Paypal then we have this PaypalProcessorclass.

这样我们就可以轻松地交换PaymentProcessorInterface实现。假设我们想将支付处理器更改为 Paypal,那么我们就有了这个PaypalProcessor类。

<?php

namespace App;

class PaypalProcessor implements PaymentProcessorInterface
{
    public function pay()
    {
        return 'pay with paypal';
    }
}

All we have to do is update the binding:

我们所要做的就是更新绑定:

$this->app->bind(\App\PaymentProcessorInterface::class, function () {
    return new \App\PaypalProcessor();
});

Hope this gives you some ideas.

希望这能给你一些想法。