为简洁起见,省略了命名空间。。。
我已经编写了以下服务提供商,并在config/app.php中注册:
class OfferServiceProvider extends ServiceProvider
{
public function register()
{
$this->registerLossControlManager();
}
protected function registerLossControlManager()
{
$this->app->bind('LossControlInterface', 'LossControl');
}
}
这是我的LosControlInterface
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
我似乎无法将接口依赖性注入自定义类,但当依赖性注入控制器时,我可以。
有没有想过我做错了什么,或者为了让自动解决方案发挥作用而遗漏了什么?
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');
}
}
这样做的好处是,您的控制器与创建优惠背后的逻辑完全脱钩,同时允许您在创建优惠的过程中增加任何必要的复杂性。
在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]);
在laravel 5.4中(https://github.com/laravel/framework/pull/18271)您需要使用IoC容器的新makeWith方法。
App::makeWith( 'App'MyNameSpace'MyClass', [ $id ] );
如果你仍然使用5.3或更低版本,以上答案将有效。