【问题标题】:How to inject multiple classes that share the same interface in Laravel 4如何在 Laravel 4 中注入多个共享相同接口的类
【发布时间】:2013-10-22 07:23:32
【问题描述】:

假设我有一个接口CrawlerInterface,实现PageCrawlerFeedCrawler;如果我们碰巧在一个控制器中需要这两个类,那么如何通过构造函数注入来实现呢?

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

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


更新:

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


我的后续问题:

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

【问题讨论】:

  • 正如一些人所指出的,这实际上可能是一种代码味道(我自己也遇到过这种味道!)。您能否包括为什么您选择使用接口来实现?您的 2 个实现之间有什么不同?正如 Antonio 所指出的,您实际上可能想要使用具体的类来实现依赖项,或者重新考虑一下代码架构。也许我们可以帮助解决使这个问题成为一个问题的底层架构。
  • @fideloper thx,认为我有解决问题的方法;但我仍然对我们能采取这种方法多远感到有些困惑,请参阅我的后续问题。
  • 我真的认为一个接口有多个实现并不是一件坏事。但是,如果是这种情况并且您想同时使用许多实现,那么应该有一个基于它们的使用的原因。例如,我的应用程序中可能有 2 个缓存:一个用于查询,另一个用于我的视图。然后我对查询使用“APCCache”,对视图使用“FileCache”,但是正如你所看到的,我不关心实现,我只关心我有一个“cache.queries”和“cache.views” .重要的是用途。
  • @MatthieuNapoli 我想知道如何与服务提供商一起管理这个......
  • 我不了解 Laravel,但通常 DI 容器提供“命名服务”的概念,即服务不是由类/接口名称标识而是由任意名称标识。我会从容器中请求“cache.queries”条目,而不是“Doctrine\Cache\CacheInterface”条目。

标签: php dependency-injection laravel laravel-4 simplepie


【解决方案1】:

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

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

对于控制器:

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

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

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

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

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

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

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

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

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

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

【讨论】:

  • 说我使用CrawlerInterface.page - 这就像PageCrawler 的别名一样,它比直接注入类有优势吗?
  • @bitinn 在你的例子中,是的,它是一样的,你不应该那样做。该名称应该是关于不同的用法。例如,在我的应用程序中,我有一个“logger.main”(日志错误)和一个“logger.queries”(日志数据库查询)。然后我根据我想要记录的内容来选择我想要的记录器,而不是取决于我是想记录到文件、系统日志还是FirePHP
  • 因此,当您拥有用于不同事物的同种对象时,您应该“命名”您的服务。但是,在您的情况下,如果您只想让“所有爬虫”来爬取所有可能的来源,那么第二种解决方案(在我的回答中)会更好。
  • 似乎没有人想出更好的选择,我的第一个赏金是你的,谢谢你的帮助!
【解决方案2】:

好吧,假设你有一个CrawlerController

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

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

界面

interface CrawlerInterface{}

该接口的具体实现称为PageCrawlerFeedCrawler

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

您可以通过编写类似的服务定位器来注入依赖项

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

但正如其他人所建议的那样,您应该重新考虑您的逻辑,仅在这种情况下使用它 建筑是不可避免的

【讨论】:

  • 嗯,我从来没有见过这样的美国案例,我们真的应该从App::bind闭包中返回控制器吗?它有什么含义?
  • 由于我从不使用这种方法,我不能确定是否有任何影响,但乍一看,您手动提供依赖项而不是 laravel 通过反射来完成它,所以不应该任何问题
【解决方案3】:

我认为在这种情况下界面对您没有帮助。

通过做:

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

你需要选择一个:

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

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

然后 Laravel 会注入它:

class CrawlerController {

    public function __construct(CrawlerInterface $crawler)
    {
    }

}

要两者兼得,你有 2 个选择

-有2个不同的接口

-直接注入实现:

class CrawlerController {

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

}

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-01
    • 2011-02-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多