在laravel外墙上使用依赖注入

myo*_*yol 43 php dependency-injection laravel laravel-facade

我已经阅读了许多消息来源,暗示laravel facade最终是为了方便而存在,而且应该注入这些类以允许松散耦合.甚至Taylor Otwell也有一篇文章解释了如何做到这一点.似乎我不是唯一一个想到这一点的人.

use Redirect;

class Example class
{
    public function example()
    {
         return Redirect::route("route.name");
    }
}
Run Code Online (Sandbox Code Playgroud)

会成为

use Illuminate\Routing\Redirector as Redirect;

class Example class
{
    protected $redirect;

    public function __constructor(Redirect $redirect)
    {
        $this->redirect = $redirect
    }

    public function example()
    {
         return $this->redirect->route("route.name");
    }
}
Run Code Online (Sandbox Code Playgroud)

这很好,除了我开始发现一些构造函数和方法开始采用四个+参数.

由于Laravel IoC 似乎只注入类构造函数和某些方法(控制器),即使我有相当精益的函数和类,我发现类的构造函数正在填充所需的类,然后将其注入到需要的方法.

现在我发现如果我继续这种方法,我将需要自己的IoC容器,如果我使用像laravel这样的框架,感觉就像重新发明轮子一样?

例如,我使用服务来控制业务/视图逻辑而不是处理它们的控制器 - 它们只是路由视图.所以控制器首先取其对应的service,然后是parameter其url.一个服务功能还需要检查表单中的值,因此我需要RequestValidator.就像那样,我有四个参数.

// MyServiceInterface is binded using the laravel container
use Interfaces\MyServiceInterface;
use Illuminate\Http\Request;
use Illuminate\Validation\Factory as Validator;

...

public function exampleController(MyServiceInterface $my_service, Request $request, Validator $validator, $user_id) 
{ 
    // Call some method in the service to do complex validation
    $validation = $my_service->doValidation($request, $validator);

    // Also return the view information
    $viewinfo = $my_service->getViewInfo($user_id);

    if ($validation === 'ok') {
        return view("some_view", ['view_info'=>$viewinfo]);
    } else {
        return view("another_view", ['view_info'=>$viewinfo]);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是一个例子.实际上,我的许多构造函数已经注入了多个类(模型,服务,参数,外观).我已经开始将构造函数注入(适用时)"卸载"到方法注入,并让调用这些方法的类使用它们的构造函数来注入依赖项.

我被告知,方法或类构造函数的四个以上参数作为经验法则是不好的做法/代码味道.但是如果你选择注入laravel外墙的路径,我看不出你怎么能真正避免这种情况.

我有这个想法错了吗?我的课程/职能不够精益吗?我错过了laravels容器的要点还是我真的需要考虑创建自己的IoC容器?一些其他的答案似乎在laravel容器能消除我的问题暗示?

也就是说,似乎没有就这个问题达成明确的共识......

Ste*_*eve 23

这是构造函数注入的好处之一 - 当类很多时,它变得很明显,因为构造函数参数变得太大了.

要做的第一件事就是拆分那些责任太多的控制器.

假设你有一个页面控制器:

Class PageController
{

    public function __construct(
        Request $request,
        ClientRepositoryInterface $clientrepo,
        StaffRepositortInterface $staffRepo
        )
    {

     $this->clientRepository = $clientRepo;
     //etc etc

    }

    public function aboutAction()
    {
        $teamMembers = $this->staffRepository->getAll();
        //render view
    }

    public function allClientsAction()
    {
        $clients = $this->clientRepository->getAll();
        //render view
    }

    public function addClientAction(Request $request, Validator $validator)
    {
        $this->clientRepository->createFromArray($request->all() $validator);
        //do stuff
    }
}
Run Code Online (Sandbox Code Playgroud)

这是分成两个控制器的主要候选者,ClientController并且AboutController.

一旦你完成了,如果你仍然有太多的*依赖,那么它是时候寻找我称之为间接依赖的东西(因为我不能想到它们的正确名称!) - 依赖类没有直接使用的依赖项,而是传递给另一个依赖.

这方面的一个例子是addClientAction- 它需要一个请求和一个验证器,只是将它们传递给clientRepostory.

我们可以通过创建一个专门用于从请求创建客户端的新类来减少因素,从而减少我们的依赖关系,并简化控制器和存储库:

//think of a better name!
Class ClientCreator 
{
    public function __construct(Request $request, validator $validator){}

    public function getClient(){}
    public function isValid(){}
    public function getErrors(){}
}
Run Code Online (Sandbox Code Playgroud)

我们的方法现在变成:

public function addClientAction(ClientCreator $creator)
{ 
     if($creator->isValid()){
         $this->clientRepository->add($creator->getClient());
     }else{
         //handle errors
     }
}
Run Code Online (Sandbox Code Playgroud)

关于什么数量的依赖关系太多,没有严格的规则.好消息是如果你使用松散耦合构建你的应用程序,重新分解相对简单.

我宁愿看到一个构造函数有6个或7个依赖项,而不是无参数的构造函数和一堆隐藏在整个方法中的静态调用