在Laravel 4中使用Facade和注入依赖项的问题

时间:2013-09-21 17:12:10

标签: php dependency-injection laravel-4 facade service-provider

我遇到一个问题,让Facade正常工作,并将依赖注入到底层类中。

我有一个名为'Listing'的类。它有一个名为'AdvertRepository'的依赖项,它是一个接口,一个名为EloquentAdvert的类实现了该接口。这三个类的代码在这里:

// PlaneSaleing \ Providers \ Listing.php

<?php namespace PlaneSaleing\Providers;

use PlaneSaleing\Repositories\Advert\AdvertRepository;

class Listing {

    protected $advert;

    public function __construct (AdvertRepository $advert_repository) {
        $this->advert = $advert_repository;
    }

    public function test() {
            $this->advert->test();
    }

    public function test2() {
        echo "this has worked";
    }
}

// PlaneSaleing \ Repositories \ Advert \ AdvertRepository.php

<?php namespace PlaneSaleing\Repositories\Advert;

interface AdvertRepository {

    public function test();

}

// PlaneSaleing \ Repositories \ Advert \ EloquentAdvert.php;

<?php namespace PlaneSaleing\Repositories\Advert;

class EloquentAdvert implements AdvertRepository {

    public function test() {
        echo 'this has worked';
    }
}

然后我创建了一个名为ListingServiceProvider.php的服务提供程序,它具有以下代码:

// PlaneSaleing / Providers / ListingServiceProvider.php

<?php  namespace PlaneSaleing\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\App;

class ListingServiceProvider extends ServiceProvider {

    public function register() {

        App::bind('PlaneSaleing\Repositories\Advert\AdvertRepository', 'PlaneSaleing\Repositories\Advert\EloquentAdvert');

    }
}

我还将其添加到app.php

中的ServiceProviders数组中

现在,如果我将List作为依赖项注入控制器并调用测试方法(如下所示),Laravel会正确检测依赖项,通过其绑定实例化EloquentAdvert并显示“这已经有效”。

// Controllers / TestController.php

use PlaneSaleing\Providers\Listing;

class TestController extends BaseController {

    protected $listing;

    public function __construct(Listing $listing) {
        $this->listing = $listing;
    }

    public function test1() {
        $this->listing->test();
    }
}

现在,我为Listing创建了一个facade。我添加了一个新的Facade,如下所示,并在app.php中添加了一个别名:

// PlaneSaleing \ Providers \ ListingFacade.php

<?php  namespace PlaneSaleing\Providers;

use Illuminate\Support\Facades\Facade;

class ListingFacade extends Facade {

    protected static function getFacadeAccessor() {

        return 'Listing';
    }
}

我还在ListingServiceProvider.php中添加了以下新行:

<?php  namespace PlaneSaleing\Providers;

use PlaneSaleing\Repositories\Advert\AdvertRepository;
use PlaneSaleing\Repositories\Advert\EloquentAdvert;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\App;

class ListingServiceProvider extends ServiceProvider {

    public function register() {

        App::bind('PlaneSaleing\Repositories\Advert\AdvertRepository', 'PlaneSaleing\Repositories\Advert\EloquentAdvert');

        // New lines...
        $this->app['Listing'] = $this->app->share(function() {
            return new Listing(new AdvertRepository);
        });
    }
}

现在......如果我调用Listing :: test(),我会收到以下错误:Cannot instantiate interface PlaneSaleing\Repositories\Advert\AdvertRepository

如果我调用了Listing :: test2(),我得到'这个有效',所以看起来Facade工作正常。

似乎当通过Facade访问Listing时,AdvertRepository和EloquentAdvert之间的绑定不起作用。我在ServiceProvider中查看了我的代码,认为这是问题所在,但我无法弄明白。

Facade和装订在单独测试时都有效,但在两者同时使用时都没有。

任何想法???

2 个答案:

答案 0 :(得分:3)

好的,所以我已经弄明白......对于那些遇到类似问题的人......

违规声明在ListingServiceProvider.php中,内容如下:

$this->app['Listing'] = $this->app->share(function() {
    return new Listing(new AdvertRepository);
});

错误是new AdvertRepository语句。原因是,我们告诉php直接实例化接口'AdvertRepository'。相反,我们需要告诉Laravel实例化“AdvertRepository”接口的适当实现。为此,我们使用App::make('AdvertRepository')。这样,Laravel使用先前声明的绑定来实例化正确的实现。

答案 1 :(得分:0)

如果构造函数没有注入类,则必须告诉Laravel在需要实例化特定接口时将使用哪个类:

将它放在过滤器或绑定文件中:

App::bind('PlaneSaleing\Repositories\Advert\AdvertRepository', function()
{
    return new PlaneSaleing\Repositories\Advert\EloquentAdvert;
});