【问题标题】:Issue with Facade and injected dependency in Laravel 4Laravel 4 中外观和注入依赖的问题
【发布时间】:2013-09-26 22:29:51
【问题描述】:

我在让 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 数组中

现在,如果我将 Listing 作为依赖项注入控制器并调用测试方法(如下所示),Laravel 正确检测到依赖项,通过其绑定实例化 EloquentAdvert 并显示“this has working”。

// 控制器/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();
    }
}

现在,我为列表创建了一个外观。我添加了一个新的外观如下,并在 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 工作正常。

似乎当通过其外观访问列表时,AdvertRepository 和 EloquentAdvert 之间的绑定不起作用。我在 ServiceProvider 中查看了我的代码,认为这是问题所在,但我无法弄清楚。

外观和绑定在单独测试时都有效,但在同时使用时则无效。

有什么想法吗???

【问题讨论】:

  • 我不确定这就是你的意思,但请记住,Facades 是依赖注入的替代方案,通常不结合使用。如果要使用 DI,请注入 Facade 底层的类而不是 Facade 本身。根据您的回答,我认为您理解这一点,但我想指出这一点。

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


【解决方案1】:

好的,所以我想通了...对于那些遇到类似问题的人...

违规语句在 ListingServiceProvider.php 中,内容如下:

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

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

【讨论】:

  • 对不起,你能告诉我你到底做了什么吗?我正在运行这个完全相同的问题。所以你做了什么而不是new AdvertRepository?你把App::make('AdvertRepository')放在哪里了,你又是如何返回new Listing的?
【解决方案2】:

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

将其放入您的过滤器或绑定文件中:

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

【讨论】:

  • 但是我的 ListingServiceProvider 文件中有那个(或具有这种效果的代码)...?
  • 是的,但我会试一试,因为 Laravel 仍然不知道如何实例化该存储库。由于您的外观正在工作,它应该被绑定,但您仍然收到此错误,因此,该特定绑定有问题。
  • 你会建议我在哪里插入该代码(在我的服务提供商之上)?
  • 我会尝试将它添加到 app/start/global.php,那里已经有一些(单例)绑定...
猜你喜欢
  • 1970-01-01
  • 2015-03-02
  • 2019-06-13
  • 2013-05-10
  • 2015-11-21
  • 2016-05-18
  • 2014-05-27
  • 2017-01-11
  • 2013-08-25
相关资源
最近更新 更多