【问题标题】:Laravel ioc automatic resolution - works from controller but not from custom classLaravel ioc 自动解析 - 适用于控制器但不适用于自定义类
【发布时间】:2014-10-26 17:36:02
【问题描述】:

为简洁起见省略了命名空间...

我写了如下服务提供者并在config/app.php中注册:

class OfferServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->registerLossControlManager();
    }

    protected function registerLossControlManager()
    {
        $this->app->bind('LossControlInterface', 'LossControl');
    }
}

这是我的 LossControlInterface

interface LossControlInterface
{
    /**
     * @param int $demandId
     * @param float $offerTotal
     * @param float $productTotal
     * @param null|int $partnerId
     * @return mixed
     */
    public function make($demandId, $offerTotal, $productTotal, $partnerId = null);

    /**
     * @return float
     */
    public function getAcceptableLoss();

    /**
     * @return bool
     */
    public function isAcceptable();

    /**
     * @return bool
     */
    public function isUnacceptable();

    /**
     * @return null
     */
    public function reject();
}

现在在控制器中,我可以如下注入 LossController:

use LossControlInterface as LossControl;

class HomeController extends BaseController {
   public function __construct(LossControl $lossControl)
    {
        $this->lossControl = $lossControl;
    }

    public function getLossThresholds()
    {
        $lossControl = $this->lossControl->make(985, 1000, null);

        var_dump('Acceptable Loss: ' . $lossControl->getAcceptableLoss());
        var_dump('Actual Loss: ' . $lossControl->calculateLoss());
        var_dump('Acceptable? ' . $lossControl->isAcceptable());

    }
}

但是,如果我尝试从命令调用的自定义类中依赖注入 LossControlInterface:

[2014-09-02 13:09:52] development.ERROR: exception 'ErrorException' with message 'Argument 11 passed to Offer::__construct() must be an instance of LossControlInterface, none given, called in /home/vagrant/Code/.../ProcessOffer.php on line 44 and defined' in /home/vagrant/Code/.../Offer.php:79

似乎我无法将接口依赖注入到自定义类中,但是当依赖注入到控制器时我可以。

对我做错了什么或忽略了让自动解决方案起作用有什么想法吗?

【问题讨论】:

  • 你能发布创建自定义类的代码吗?它是在服务提供商内部还是在您的工匠命令中创建的?
  • 它是从 artisan 命令中创建的。命令/ProcessOffer.php:private function setOffer(Offer $offer = null) {$this->processOffer = $offer ?: new Offer();}

标签: php laravel repository-pattern ioc-container


【解决方案1】:

IoC 在控制器中是自动的,您不会看到注入,因为 Laravel 会为您处理控制器的构建。当使用 new 关键字创建任何其他自定义类时,您仍然需要将所有需要的参数发送到它的构造函数:

$myClass = new ClassWithDependency( app()->make('Dependency') );

您可以在一定程度上隐藏这一点,方法是通过服务提供商汇集您的自定义类的创建:

// Your service provider
public function register()
{
    $this->app->bind('ClassWithDependency', function($app) {
        return new ClassWithDependency( $app->make('Dependency') );
    });
}

然后让 IoC 在您需要时制作它:

$myClass = app()->make('ClassWithDepenency');

在您的情况下,您可以将代码更改为如下所示:

private function setOffer(Offer $offer = null) {
    $this->processOffer    = $offer ?: 
        new Offer( app()->make('LossControlInterface') );
}

一种更简洁的方法可能是创建一个服务提供者和一个OfferFactory,它会被注入到您的控制器中。然后,控制器可以在需要时请求工厂创建报价:

// Controller
public function __construct(OfferFactory $offerFactory)
{
    $this->offerFactory = $offerFactory;
}

public function setOffer(Offer $offer = null)
{
    $this->processOffer = $offer ?: $this->offerFactory->createOffer();
}

// OfferFactory
class OfferFactory
{
    public function createOffer()
    {
        return app()->make('Offer');
    }
}

这样做的好处是将您的控制器与创建报价背后的逻辑完全分离,同时让您有机会为创建报价的过程添加任何必要的复杂性。

【讨论】:

    【解决方案2】:

    在 Laravel 5.2 中,针对您的特定问题最简单的解决方案是替换

    new Offer();
    

    App::make('Offer');
    

    甚至更短

    app('Offer');
    

    它将使用 Laravel Container 来处理依赖关系。

    但是,如果您想将其他参数传递给 Offer 构造函数,则需要将其绑定到您的服务提供者中

    App::bind('Offer', function($app, $args) {
        return new Offer($app->make('LossControl'), $args);
    });
    

    瞧,现在你可以写了

    app('Offer', [123, 456]);
    

    【讨论】:

      【解决方案3】:

      在 laravel 5.4 (https://github.com/laravel/framework/pull/18271) 中你需要使用 IoC 容器的新 makeWith 方法。

      App::makeWith( 'App\MyNameSpace\MyClass', [ $id ] );
      

      如果你还在使用 5.3 或更低版本,以上答案都可以。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-07
        • 1970-01-01
        • 2019-10-30
        • 2020-03-11
        • 2012-10-30
        相关资源
        最近更新 更多