Laravel:构建时目标不可实例化

Laravel: Target is not instantiable while building

抱歉,如果该问题重复,但我在 Whosebug 中阅读了很多相关问题,但 none 解决了我的问题:

我创建了一个有效的 Artisan 命令,我注入了一个 Kafka 客户端服务作为第一个参数和一个具体的 class,BudgetsTransformer,作为第二个参数

class ConsumeBudgetsCommand extends Command {
    public function __construct(FKafka $kafkaClient, BudgetsTransformer $transformer)
    {
        $this->kafkaClient = $kafkaClient;
        $this->transformer = $transformer;

        parent::__construct();
    }
}

AppServiceProvider class 看起来像:

class AppServiceProvider extends ServiceProvider
{

    public function register()
    {
        $this->app->bind('kafka.client', function ($app) {
            return new \Weq\FKafka\FKafka();
        });

        $this->app->bind('budget.transformer', function ($app) {
            return new BudgetsTransformer();
        });

    }

    public function boot()
    {
        $this->app->bind('consume:budgets', function ($app) {
            return new ConsumeBudgetsCommand($app['kafka.client'], $app['budget.transformer']);
        });

        $this->commands('consume:budgets');
    }
}

到目前为止一切正常...然后我决定创建一个 TransformerInterfaceBudgedTransformer 实现(其他未来的变形金刚将实现它):

class BudgetsTransformer implements TransformerInterface
{
 // ...
}

我更改了命令中的签名以注入接口而不是具体 class:

class ConsumeBudgetsCommand extends Command {
    public function __construct(FKafka $kafkaClient, TransformerInterface $transformer)
    {
        $this->kafkaClient = $kafkaClient;
        $this->transformer = $transformer;

        parent::__construct();
    }
}

但是当我尝试 运行 某些 artisan 命令时出现以下问题

In Container.php line 933: Target [App\Transformers\TransformerInterface] is not instantiable while building [App\Console\Commands\ConsumeBudgetsCommand].

我 运行 以前发出以下 artisan 命令以防万一... cache:clearclear-compiledoptimize 等等,但运气不好

我做错了什么?我是否应该以我现在为传递和接口而不是具体的 class 所做的不同方式绑定 BudgetTransformer

提前感谢您的帮助

更新

按照@davit 的建议,我添加了

$this->app->bind(TransformerInterface::class, BudgetsTransformer::class);

在 AppServiceProvider::register() 中,我删除了

$this->app->bind('budget.transformer', function ($app) {
        return new BudgetsTransformer();
});

在那里,然后我在 AppServiceProvider::boot() 中更新命令绑定:

$this->app->bind('consume:budgets', function ($app) {
        return new ConsumeBudgetsCommand($app['kafka.client'], $app[TransformerInterface::class]);
});

但仍然无效,无论如何这种方法(即使有效)也无法解决问题,因为当我想添加另一个不同的转换器实现时,假设 CostTransformer 实现 TransformerInterface 总是会注入 BudgetTransformer。所以阅读 link 中的文档,我发现 Contextual Binding 可能是解决方案,所以我选择了:

$this->app
        ->when(ConsumeBudgetsCommand::class)
        ->needs(TransformerInterface::class)
        ->give(function ($app) {
            return new BudgetsTransformer();
        });

这样一来,我将能够通过注入接口将不同的转换器实现注入到不同的命令中。但是还是不行。

谁能告诉我如何准确地声明命令绑定

$this->app->bind('consume:budgets', function ($app) {
        return new ConsumeBudgetsCommand($app['kafka.client'], ???);
    });

使用那个 Contextual binding?

绑定接口必须使用这个结构https://laravel.com/docs/5.5/container#binding-interfaces-to-implementations

$this->app->bind(TransformerInterface::class, BudgetsTransformer::class);

$this->app->bind('consume:budgets', function ($app) {
    return new ConsumeBudgetsCommand($app['kafka.client'], $app->make(TransformerInterface::class));
});