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

时间:2015-10-06 19:28:56

标签: php laravel laravel-5 ioc-container laravel-5.1

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

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'));
        });
    }
}

据我了解the documentation on binding an instance,这允许我将密钥iCal绑定到服务容器,以便稍后在我的控制器或服务类中,我可以键入提示iCal并创建实例将使用服务提供商。

所以我创建了一个控制器并尝试输入提示我的实例:

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;

class CalendarInviteController extends Controller
{
    public function download(iCal $ical, $sessionId)
    {
        dd($ical);
    }
}

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

  

Class App \ Http \ Controllers \ iCal不存在

有道理,因为它应用它在控制器命名空间中寻找一个名为iCal的类,该类不存在。实例没有use语句,因为iCal只是一个文本键,所以我试着告诉它查看可能解决它的根命名空间思路:

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

我收到错误:

  

类iCal不存在

当我阅读resolving from the service container上的文档部分时,看起来我需要在控制器中做的唯一事情是输入实例的类型提示。

我误解了文档吗?

更新

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

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

2 个答案:

答案 0 :(得分:2)

正如您在docs中看到的,方法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无法实例化该类

答案 1 :(得分:1)

如果你想将依赖项注入你的控制器(这很好,所以很荣幸!)那么你需要一个接口名称来键入提示。

通常你会有一个通用接口,然后将该接口绑定到具体的实现。所以你可能有一个日历服务接口,它与你的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;
    }
}