【问题标题】:Laravel dependency injection in domain namespace域命名空间中的 Laravel 依赖注入
【发布时间】:2014-07-07 15:24:53
【问题描述】:

我在让依赖注入与依赖反转一起工作时遇到问题。我可以在构造函数中调用 App::make,并且依赖倒置工作得很好……只有当我尝试将它注入构造函数时才会出现问题。

ReflectionException Class StationsInterface does not exist

会命中此问题的 uri 将是 .../stats/station/mogreet/6

文件结构:

-app

    -controllers
        *StatsController

-Dashboard

    -Datasync

        -Interfaces
            *DatasyncInterface
            *MogreetDatasyncInterface

        -Services
            *MogreetDatasync

        *BackendServiceProvider
        *DatasyncBase

    -Repositories

        -Interfaces
            *CredentialsInterface
            *StationsInterface

        -Stations
            *DbCredentials
            *DbStations
            *FileCredentials

        -Stats

        *BackendServiceProvider
        *DbRepositoryBase

相关代码块如下:

服务提供者:

<?php namespace Dashboard\Repositories;

use Illuminate\Support\ServiceProvider;

class BackendServiceProvider extends ServiceProvider {

    public function register() {

        // Service Providers located in Stats directory
        $this->app->bind('StatsDailyInterface', 'Dashboard\Repositories\Stats\DbStatsDaily');
        //$this->app->bind('StatsMonthlyRepository', 'Dashboard\Repositories\Stats\DbStatsMonthly');
        //$this->app->bind('StatsYearlyRepository', 'Dashboard\Repositories\Stats\DbStatsYearly');

        // Service Providers located in Stations directory
        $this->app->bind('CredentialsInterface', 'Dashboard\Repositories\Stations\FileCredentials');
        $this->app->bind('StationsInterface', 'Dashboard\Repositories\Stations\DbStations');

    }

}

Controller:请注意,在 this 的构造函数中,我使用的是 App::make 而不是注入依赖项。如果我注入依赖项,我会得到一个类解析错误,就像我在 DatasyncBase 类中所做的那样。

<?php

use Dashboard\ConrollerFacades\Facades\Services;

class StatsController extends BaseController {

    /*
    |--------------------------------------------------------------------------
    | Stats Controller
    |--------------------------------------------------------------------------
    |
    | Pull and display stats for station, market, or corporate views
    |
    |   
    |
    */

    private $StationModel;

    public function __construct() {
        $this->StationModel = App::make('StationsInterface');
    }

    /**
    * Pulls stats for an individual station
    *
    * @param string $service of station
    * @param integer $id of station
    * 
    * @return void
    */
    public function station( $service, $stationId ) {

        $this->Service = $this->serviceSelector($service);

        if(!$this->Service) throw new Exception('Unknown Service Selected', 1);

        $this->Service->init($stationId);

        exit();

    }

    /**
    * Pulls stats for a Market
    *
    * @param integer $id of market
    *
    * @return void
    */
    public function market( $service, $marketId ) {

        $this->Service = $this->serviceSelector($service);

        if(!$this->Service) throw new Exception('Unknown Service Selected', 1);

        foreach($StationModel->getStationIdsByMarket($marketId) as $station) {
            $this->Service->init($station);
        } 

        exit();

    }

    /**
    * Pulls stats for Corporate (all stations)
    * 
    * @return void
    */
    public function corporate( $service ) {

        $this->Service = $this->serviceSelector($service);

        if(!$this->Service) throw new Exception('Unknown Service Selected', 1);

        foreach($StationModel->getAllStationIds() as $station) {
            $this->Service->init($station);
        }

        exit();

    }

    private function serviceSelector($service) {

        switch(strtolower($service)) {
            case 'brightcove': return App::make('BrightCoveDatasyncInterface'); break;
            case 'facebook': return App::make('FacebookDatasyncInterface'); break;
            case 'googleanalytics': return App::make('GoogleAnalyticsDatasyncInterface'); break;
            case 'liquidcompass': return App::make('LiquidCompassDatasyncInterface'); break;
            case 'mogreet': return App::make('MogreetDatasyncInterface'); break;
            case 'twitter': return App::make('TwitterDatasyncInterface'); break;
            default: return false; break;
        }

    }

}

这个类的构造函数是发生依赖注入问题的地方。 DatasyncBase:这个类从不直接实例化,它由像 MogreetDatasync 这样的服务类继承。将构造函数移至 MogreetDatasync 类进行测试并不能解决问题。

<?php namespace Dashboard\Datasync;

use Dashboard\Repositories\Interfaces\StationsInterface;
use Dashboard\Repositories\Interfaces\CredentialsInterface;

class DatasyncBase {

    protected $Station;
    protected $Credentials;

    protected $results;

    protected $stats;

    public function __construct(StationsInterface $Station , CredentialsInterface $Credentials) {
        $this->Station = $Station;
        $this->Credentials = $Credentials;
        $this->stats = array();
    }

    public function __destruct() {

        unset($this->results);
        unset($this->stats);

    }

    public function init() {}

    protected function fetch($uri = null, $post_fields = null) {

        $cURL = curl_init();
        curl_setopt($cURL, CURLOPT_URL, $uri);
        curl_setopt($cURL, CURLOPT_CUSTOMREQUEST, 'GET');
        curl_setopt($cURL, CURLOPT_POSTFIELDS, $post_fields);
        $this->results = curl_exec($cURL);
        curl_close($cURL); 

    }

}

数据同步服务:

<?php namespace Dashboard\Datasync\Services;

use Dashboard\Datasync\DatasyncBase;
use Dashboard\Datasync\Interfaces\MogreetDatasyncInterface;

class MogreetDatasync extends DatasyncBase implements MogreetDatasyncInterface {

    public function init($stationId) {}
    protected function uri() {}
    protected function parse() {}
    protected function write() {}

}

【问题讨论】:

  • 你在哪里实例化 DatasyncBase 类?如果你想让 laravel 从 IOC 容器中注入依赖项,你是否意识到你必须 App::make() ?
  • DatasyncBase类只是Datasync的一个父类,所以通过MogreetDatasync的继承来实例化。我不知道您必须 App::make() 来注入依赖项,我的大多数示例仅使用绑定。我将开始研究这种方法,但如果你有一个很好的例子/教程,你可以指点我,那将不胜感激。
  • 类型提示的自动注入是 Laravel 所做的,而不是 PHP 所做的。您可以从控制器构造函数注入的原因是因为它是使用 Laravel 的 IOC 容器的 build() 方法实例化的。看看那节课,你会更好地理解发生了什么。我什至相信 Laracasts 有一个关于它的截屏视频 :)
  • 我正在尝试将依赖倒置与依赖注入一起使用。需要使用 App::make 使得 IOC 容器能够解析绑定。我仍然无法让依赖反转工作。我将更新问题以反映所做的代码更改以及目录结构。

标签: php laravel-4 ioc-container


【解决方案1】:

这个问题的答案是 ServiceDatasyncInterfaces 的闭包。以前我是这样定义绑定的:

$this->app->bind('MogreetDatasyncInterface', 'Dashboard\Datasync\Services\MogreetDatasync');

但是,这不允许 IoC “递归”注入反转依赖项,您必须使用 App::make('InversionInterface') 让 IoC 真正正确地解决此问题。

<?php namespace Dashboard\Datasync;

use Illuminate\Support\ServiceProvider;

use Dashboard\Datasync\Services\BrightCoveDatasync;
use Dashboard\Datasync\Services\FacebookDatasync;
use Dashboard\Datasync\Services\GoogleAnalyticsDatasync;
use Dashboard\Datasync\Services\LiquidCompassDatasync;
use Dashboard\Datasync\Services\MogreetDatasync;
use Dashboard\Datasync\Services\TwitterDatasync;

class BackendServiceProvider extends ServiceProvider {

    public function register() {

        $this->app->bind('BrightCoveDatasyncInterface', function() { return new BrightCoveDatasync( $this->app->make('StationsInterface'), $this->app->make('CredentialsInterface') ); });
        $this->app->bind('FacebookDatasyncInterface', function() { return new FacebookDatasync( $this->app->make('StationsInterface'), $this->app->make('CredentialsInterface') ); });
        $this->app->bind('GoogleAnalyticsDatasyncInterface', function() { return new GoogleAnalyticsDatasync( $this->app->make('StationsInterface'), $this->app->make('CredentialsInterface') ); });
        $this->app->bind('LiquidCompassDatasyncInterface', function() { return new LiquidCompassDatasync( $this->app->make('StationsInterface'), $this->app->make('CredentialsInterface') ); });
        $this->app->bind('MogreetDatasyncInterface', function() { return new MogreetDatasync( $this->app->make('StationsInterface'), $this->app->make('CredentialsInterface') ); });
        $this->app->bind('TwitterDatasyncInterface', function() { return new TwitterDatasync( $this->app->make('StationsInterface'), $this->app->make('CredentialsInterface') ); });

    }

}

这是一个相当小的问题,但您需要在包含要注入的类的文件中使用正确的接口。我的 DatasyncBase 文件现在看起来像这样:

<?php namespace Dashboard\Datasync;

use Dashboard\Repositories\Interfaces\StationsInterface;
use Dashboard\Repositories\Interfaces\CredentialsInterface;

class DatasyncBase {

    protected $Station;
    protected $Credentials;

    protected $results;

    protected $stats;

    public function __construct(StationsInterface $Station, CredentialsInterface $Credentials) {
        $this->Station = $Station;
        $this->Credentials = $Credentials;
        $this->stats = array();
    }

    public function __destruct() {

        unset($this->results);
        unset($this->stats);

    }

    public function init() {}

    protected function fetch($uri, $post_fields = '') {

        $cURL = curl_init();
        curl_setopt($cURL, CURLOPT_URL, $uri);
        curl_setopt($cURL, CURLOPT_CUSTOMREQUEST, 'GET');
        curl_setopt($cURL, CURLOPT_POSTFIELDS, $post_fields);
        $this->results = curl_exec($cURL);
        curl_close($cURL); 

    }

}

您可以在此处找到有关 ServiceProvider 的更多信息: https://laracasts.com/lessons/service-providers-decoded

【讨论】:

    猜你喜欢
    • 2019-04-26
    • 2016-04-28
    • 2016-06-11
    • 2023-03-25
    • 2016-10-05
    • 2016-05-28
    • 2021-02-20
    • 2017-11-20
    • 1970-01-01
    相关资源
    最近更新 更多