注入绑定到服务容器的实例


Injecting an instance bound to the service container

我有一个服务提供者,我想用它来绑定一个类的实例到服务容器:

namespace App'Providers;
use Eluceo'iCal'Component'Calendar;
use Illuminate'Support'ServiceProvider;
class IcalProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->instance('iCal', function () {
            return new Calendar(config('calendar.name'));
        });
    }
}

根据我对绑定实例的文档的理解,这允许我将键iCal绑定到服务容器,以便稍后在我的控制器或服务类中我可以键入提示iCal,并且将使用在服务提供者中创建的实例。

所以我创建了一个控制器并尝试键入hint my instance:

namespace App'Http'Controllers;
use App'Http'Controllers'Controller;
class CalendarInviteController extends Controller
{
    public function download(iCal $ical, $sessionId)
    {
        dd($ical);
    }
}

但是当我这样做的时候,我得到了错误:

类App'Http'Controllers'iCal不存在

是有意义的,因为它适用于在控制器命名空间中寻找一个名为iCal的类,而这个类并不存在。没有使用语句的实例,因为iCal只是一个文本键,所以我试着告诉它看根名称空间认为可能会修复它:

public function download('iCal $ical, $sessionId)

,我得到错误:

iCal类不存在

当我阅读文档中关于从服务容器解析的部分时,看起来我需要在控制器中做的唯一一件事就是输入提示来获取实例。

我是否误解了文档?

更新

我还应该提到,我确实在我的config/app.php文件中添加了我的服务提供商。

同样,当我创建一个接口时,将其绑定到服务容器,编辑供应商代码以实现该接口,并注入该接口,而不是它工作,但这需要我编辑我不想要的供应商代码。

正如您在文档中看到的,方法instance需要一个密钥和一个对象实例来在容器中注册。所以,如果你想在容器中注册一个特定的实例,注册应该是:

namespace App'Providers;
use Eluceo'iCal'Component'Calendar;
use Illuminate'Support'ServiceProvider;
class IcalProvider extends ServiceProvider
{
    public function register()
    {
        //register a specific instance of the Calendar class in the container
        $this->app->instance('iCal', new Calendar(config('calendar.name') );
    }
}

这样你可以用

返回实例:
 $cal = 'App::make('iCal');

如果你的目的是在控制器方法中提示类的类型,并且你想从服务容器中解析之前注册的实例,你可以这样做:

namespace App'Providers;
use Eluceo'iCal'Component'Calendar;
use Illuminate'Support'ServiceProvider;
class IcalProvider extends ServiceProvider
{
    public function register()
    {
        //the key will be 'Eluceo'iCal'Component'Calendar'
        $this->app->instance( Calendar::class, new Calendar(config('calendar.name') );
    }
}

现在,在控制器中:

namespace App'Http'Controllers;
//important: specify the Calendar namespace
use Eluceo'iCal'Component'Calendar;
class CalendarInviteController extends Controller
{
    public function download(Calendar $ical, $sessionId)
    {
        dd($ical);
    }
}

这样Laravel就会看到你想要一个Calendar对象,它会尝试从服务容器中获取它,看看是否存在这个键的绑定:(因为这是你在控制器中指定的类的命名空间)

Eluceo'iCal'Component'Calendar

且绑定存在!因为你已经将这个密钥绑定到服务提供商的服务容器中,所以Laravel将返回你注册的实例。

在您提供的代码中,您提示了类iCal,但该类在任何地方都不存在,因此Laravel无法实例化类

如果你想在你的控制器中注入依赖项(这很好,所以很好!),那么你需要一个接口名来提示类型。

通常你会有一个泛型接口,然后将该接口绑定到一个具体的实现。因此,您可能有一个日历服务接口,它绑定到您的iCal实现。像这样:
use Eluceo'iCal'Component'Calendar;
class CalendarServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->bind('App'Services'Calendar', function ($app) {
            return new Calendar(config('calendar.name'));
        });
    }
    public function provides()
    {
        return ['App'Services'Calendar'];
    }
}
只要你在你的config/app.php文件中注册你的服务提供商,你现在就可以在类中输入提示你的日历依赖:
use App'Services'Calendar;
class InvitationController extends Controller
{
    protected $calendar;
    public function __construct(Calendar $calendar)
    {
        $this->calendar = $calendar;
    }
}