Laravel ioc自动分辨率 - 从控制器工作,但不从自定义类工作

Gra*_*avy 5 php ioc-container repository-pattern laravel

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

我编写了以下服务提供程序并在config/app.php中注册:

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

    protected function registerLossControlManager()
    {
        $this->app->bind('LossControlInterface', 'LossControl');
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的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();
}
Run Code Online (Sandbox Code Playgroud)

现在在控制器中,我可以按如下方式注入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());

    }
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我尝试依赖从命令调用的自定义类中注入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
Run Code Online (Sandbox Code Playgroud)

看起来好像我无法将接口注入到自定义类中,但是当依赖注入控制器时我可以.

关于我做错了什么或者没有让自动解决方案工作的任何想法?

Jef*_*ert 9

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

$myClass = new ClassWithDependency( app()->make('Dependency') );
Run Code Online (Sandbox Code Playgroud)

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

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

然后让IoC在您需要时随时进行:

$myClass = app()->make('ClassWithDepenency');
Run Code Online (Sandbox Code Playgroud)

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

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

一个可能更干净的方法可能是创建一个服务提供者,并将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');
    }
}
Run Code Online (Sandbox Code Playgroud)

这样做的好处是可以将控制器与创建商品背后的逻辑完全分离,同时允许您有一个位置来添加创建商品流程所需的任何复杂性.