哪个是使用依赖项容器的正确方法?

时间:2019-07-28 06:02:58

标签: php dependency-injection

我正在使用Slimphp-di作为容器,我一直在试图弄清楚如何autowire依赖项没有成功。

我想将App\Models\Planner.php注入App\Controllers\MealPlanner.php中,以及由不同端点/方法/动作调用的其他各种类和模型。

现在在Services.php上,我正在创建4个服务2,这些服务将传递给其他类,以及2个工厂,分别是Planner.phpMealPlanner.php,在路由器中被调用在index.php上。

现在将MealPlanner定义为服务,可以直接从$app->any('/mealplanner/{action}', \MealPlanner::class);调用它,如果删除$app->set('MealPlanner', ...),我将得到“ Callable MealPlanner不存在”,为什么可调用在那里没有进入容器?

第二,假设我想将Fruits类与Planner.php一起注入MealPlanner,为此,我必须添加一个新服务$container->set("Fruits", (){ return App\Models\Fruits.php(PDO $db, $UserId) }),然后在MealPlanner服务上将水果容器传递到那里,然后在MealPlanner控制器上将其变为:

public function __construct(App\Models\Planner $planner, App\Models\Fruits $fruits)

就个人而言,必须将它们传递通过服务容器,然后必须在控制器上进行更改,这很烦人,在这里我可能会误解。

假设我决定将上面的代码删除,取而代之的是"slim will instantiate the container",MealPlanner.php现在应该是

namespace App\Controllers;
use Psr\Container\ContainerInterface;

class MealPlanner extends InvokeAction {

  public function __construct(ContainerInterface $container){
    $this->container = $container;
  }

  public function init($request, $response, $args){
    // return something
  }    
}

我必须从容器中删除MealPlanner工厂,所以路由类定义将停止工作,并且我必须使用它的绝对路径来工作$app->any('/mealplanner/{action}', \App\Controllers\Planner::class);,现在所有服务都喜欢可通过容器访问“数据库”和“计划器”,但是我仍然必须创建服务(例如Fruits),因此无法掌握自动装配的工作方式,因为它们在类型提示时未定义绝对路径。 / p>

1 个答案:

答案 0 :(得分:1)

我创建了一个将Slim 4和Eloquent ORM结合在一起的框架,称为Willow。这是我使用PHP-DI的方法:

App.php

<?php
declare(strict_types=1);
namespace Willow\Main;
use DI\ContainerBuilder;
use Slim\Factory\AppFactory;
class App
{
    public function __construct()
    {
        // Set up Dependency Injection
        $builder = new ContainerBuilder();

        // Read in each config file to inject. See db.php below as an example
        foreach (glob(__DIR__ . '/../../config/*.php') as $definitions) {
            $builder->addDefinitions(realpath($definitions));
        }
        $container = $builder->build();

        // Get an instance of Slim\App and inject the container.
        AppFactory::setContainer($container);
        $app = AppFactory::create();
    }
}

config/db.php

<?php
declare(strict_types=1);
use Illuminate\Database\Capsule\Manager as Capsule;
use Psr\Container\ContainerInterface;
// By returning this array it sets up Capsule::class to be injected via DI
return [
    Capsule::class => function (ContainerInterface $c) {
        $eloquent = new Capsule;
        $eloquent->addConnection([
            'driver'    => env('DB_DRIVER') ?? 'mysql',
            'host'      => getenv('DB_HOST'),
            'port'      => getenv('DB_PORT') ?? '',
            'database'  => getenv('DB_NAME'),
            'username'  => getenv('DB_USER'),
            'password'  => getenv('DB_PASSWORD'),
            'charset'   => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix'    => ''
        ]);
        // Make this Capsule instance available globally via static methods
        $eloquent->setAsGlobal();
        // Setup the Eloquent ORM...
        $eloquent->bootEloquent();
        // Set the fetch mode to return associative arrays.
        $eloquent->setFetchMode(PDO::FETCH_ASSOC);
        return $eloquent;
    }
];