如何在 Laravel 控制器方法中不使用容器?

How not to use the container within Laravel controller method?

我已经开始研究 Laravel 并且我对项目中的依赖项管理有一些疑问。假设我有依赖 DependencyA 使用 DependencyB 使用 DependencyC:

<?php 

namespace Some\NamespaceOf;

use Illuminate\Container\Container;

class DependencyA {

   public function someMethod(DependencyB $b, Container $container) {
      $container->call([$b, 'doSomething']);
   }

}

class DependencyB {
   public function doSomething(DependencyC $c) {
      // ... do something with $c
   } 
}

然后,在我的控制器中:

<?php

namespace App\Http\Controllers;

use App\User;
use App\Http\Controllers\Controller;
use Some\NamespaceOf\DependencyA;
use Illuminate\Container\Container;

class SomeController extends Controller
{
    // ...

    /**
     * @param DependencyA  $a
     * @return Response
     */
    public function controllerMethod(DependencyA $a, Container $container)
    {
        $container->call([$a, 'someMethod']);
        // ...
    }

    // ...
}

我不喜欢在组件之间反复传递控制器。

在这种情况下最好的重构是什么?将控制器重写为:

<?php

namespace App\Http\Controllers;

use App\User;
use App\Http\Controllers\Controller;
use Some\NamespaceOf\DependencyA;
use Some\NamespaceOf\DependencyB;
use Illuminate\Container\Container;

class SomeController extends Controller
{
    // ...

    /**
     * @param DependencyA  $a
     * @return Response
     */
    public function controllerMethod(DependencyA $a, DependencyB $b)
    {
        $a->someMethod($b);
        // ...
    }

    // ...
}

这还不够,因为 DependencyA 还需要容器在调用 $b->doSomething() 传递它 $c 之前查找 DependencyC。我也必须编辑 DependencyA,但是我怎样才能向它注入 DependencyC

这种依赖关系形成时应该怎么办? 在组件中使用容器让我觉得违反了 IoC 原则。

感谢关注

如果我懂你;这可能会有帮助:

AppServiceProvider:

namespace App\Providers;

use App\Dependencies\DependencyA;
use App\Dependencies\DependencyB;
use App\Dependencies\DependencyC;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->bind(DependencyB::class, function ($app) {
            return new DependencyB(new DependencyC());
        });

        $this->app->bind(DependencyA::class, function ($app) {
            return new DependencyA($app->make(DependencyB::class));
        });
    }
}

DependencyA:

namespace App\Dependencies;

class DependencyA
{
    private $dependencyB;

    public function __construct(DependencyB $dependencyB)
    {
        $this->dependencyB = $dependencyB;
    }

    public function useMe()
    {
        return $this->dependencyB->useMe();
    }
}

DependencyB:

namespace App\Dependencies;

class DependencyB
{
    private $dependencyC;

    public function __construct(DependencyC $dependencyC)
    {
        $this->dependencyC = $dependencyC;
    }

    public function useMe()
    {
        return $this->dependencyC->useMe();
    }
}

DependencyC:

namespace App\Dependencies;

class DependencyC
{
    public function useMe()
    {
        echo "Used me.";
    }
}

现在,在我们的控制器中,如果我们使用 DependencyA 作为唯一的依赖; DependencyA class 和 DependencyB class 的依赖关系将被分别解析。

DependantController:

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Dependencies\DependencyA;

class DependantController extends Controller
{
    private $dependencyA;

    public function __construct(DependencyA $dependencyA)
    {
        $this->dependencyA = $dependencyA;
    }

    public function index()
    {
        $this->dependencyA->useMe();
    }
}

web.php

Route::get('dependant', 'DependantController@index');

现在,如果您访问http://127.0.0.1:8000/dependant 您将看到 Used me. 作为此实施的结果。