如何在 Laravel 4 中注入共享相同接口的多个类

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19365138/
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 08:33:54  来源:igfitidea点击:

How to inject multiple classes that share the same interface in Laravel 4

phpdependency-injectionlaravellaravel-4simplepie

提问by bitinn

Say I have an interface CrawlerInterfacewith implementation PageCrawlerand FeedCrawler; if we happen to need both classes in a controller, how can that be achieved with constructor injection?

假设我有一个CrawlerInterface带有实现PageCrawler和的接口FeedCrawler;如果我们碰巧在控制器中需要两个类,如何通过构造函数注入来实现?

Previously we use a central ServiceProviderto register (i.e. App::bind) such classes, but in most cases we only have 1 implementation of an interface, so said problem hasn't occured to us yet.

以前我们使用一个中心ServiceProvider来注册(即App::bind)这样的类,但在大多数情况下,我们只有一个接口的 1 个实现,所以我们还没有出现上述问题。

PS: I also wonder if this problem suggests we should split the controller.

PS:我也想知道这个问题是否表明我们应该拆分控制器。



Updates:

更新:

Thanks for the comments and response, to explain, said interface has only one public method: crawl($uri), and both page/feed crawler implements it as given a resource identifier, return resource.

感谢评论和回复,解释一下,该接口只有一个公共方法:crawl($uri),并且页面/提要爬虫都将其实现为given a resource identifier, return resource.



My follow up question:

我的后续问题:

Say we are in a calculatorscenario where Addition, Subtraction and Multiplication share the same interface Operation, which has only 1 public method run, at some point we will still encounter this problem right? How do we handle situation like these in general with ServiceProvider?

假设我们在一个calculator场景中,加法、减法和乘法共享相同的接口Operation,只有 1 个公共方法run,在某些时候我们仍然会遇到这个问题,对吗?我们一般如何处理这样的情况ServiceProvider

回答by Matthieu Napoli

If each crawler exists for a different reason, you can use arbitrary names for your instances, for example:

如果每个爬虫存在的原因不同,您可以为您的实例使用任意名称,例如:

App::bind('crawler.allArticles', 'PageCrawler');
App::bind('crawler.latestArticles', 'FeedCrawler');

For the controller:

对于控制器:

App::bind('CrawlerController', function($app) {
    return new CrawlerController(
        App::make('crawler.allArticles'),
        App::make('crawler.latestArticles')
    );
});

Your controller code would then use each crawler differently:

然后您的控制器代码会以不同的方式使用每个爬虫:

public function showLatestArticlesAction()
    $latestArticles = $this->latestArticlesCrawler->crawl();
    // ...
}

public function showAllArticlesAction()
    $allArticles = $this->allArticlesCrawler->crawl();
    // ...
}


If you just have a list of crawlers where each is used for the same thing, you probably want to do something like:

如果您只有一个爬虫列表,其中每个都用于相同的事情,您可能想要执行以下操作:

App::bind('crawlers', function($app) {
    return [
        App::make('PageCrawler'),
        App::make('FeedCrawler'),
    ];
});

In your controller, you'll get a list of "crawlers" by configuring it like so:

在您的控制器中,您将通过如下配置获得“爬虫”列表:

App::bind('CrawlerController', function($app) {
    return new CrawlerController(App::make('crawlers'));
});

Your controller code could be something like this:

您的控制器代码可能是这样的:

public function showArticlesAction()
    $allArticles = array();
    foreach ($this->crawlers as $crawler) {
        $allArticles = array_merge($allArticles, $this->crawler->crawl());
    }
    // ...
}

回答by Nenad

Ok lets assume you have a CrawlerController

好的,让我们假设你有一个 CrawlerController

class CrawlerController extends BaseController 
{
    protected $crawler1;
    protected $crawler2;

    public function __construct(CrawlerInterface $c1, CrawlerInterface $c2)
    {
        $this->crawler1 = $c1;
        $this->crawler2 = $c2;
    }
}

an interface

一个接口

interface CrawlerInterface{}

and concrete implementations of that intefrace called PageCrawlerand FeedCrawler

以及该接口的具体实现,称为PageCrawlerFeedCrawler

class PageCrawler implements CrawlerInterface{}
class FeedCrawler implements CrawlerInterface{}

You would inject the dependencies by writing a service locator like

您可以通过编写服务定位器来注入依赖项,例如

App::bind('CrawlerController', function($app) {
    $controller = new CrawlerController(
        new PageCrawler,
        new FeedCrawler
    );
    return $controller;
});

But as suggested by others you should rethink your logic, use it only if this kind of architecture is unavoidable

但是正如其他人建议的那样,您应该重新考虑您的逻辑,只有在这种架构不可避免时才使用它

回答by Antonio Carlos Ribeiro

I think that the interface won't help you in this case.

我认为在这种情况下界面不会帮助你。

By doing:

通过做:

App::bind('CrawlerInterface', '<implementation>');

You need to choose one:

你需要选择一个:

App::bind('CrawlerInterface', 'PageCrawler');

or

或者

App::bind('CrawlerInterface', 'FeedCrawler');

And then Laravel will inject it:

然后 Laravel 将注入它:

class CrawlerController {

    public function __construct(CrawlerInterface $crawler)
    {
    }

}

To have both you have 2 options

要同时拥有两者,您有 2 个选择

-Have 2 different interfaces

-有2个不同的接口

-Inject the implementations directly:

- 直接注入实现:

class CrawlerController {

    public function __construct(PageCrawler $pageCrawler, FeedCrawler $feedCrawler)
    {
    }

}

But I also think that, if you need something like this, you better rethink your logic.

但我也认为,如果你需要这样的东西,你最好重新思考你的逻辑。