Laravel 5 - 接口不可实例化

Laravel 5 - Interface is not instantiable

我知道这个问题被问了很多次,但是 none 个答案对我有帮助。

我在 Laravel 5

中遇到异常
BindingResolutionException in Container.php line 785:
Target [App\Contracts\CustomModelInterface] is not instantiable.

我做过没有成功的事情:

结构:

app
  - Contracts
    - CustomModelInterface.php
  - Models
    - CustomModel.php
  - Repositories
    - CustomModelRepository.php
  - Providers
    - AppRepositoryProvider.php
  - Services
    - MyService.php

App\Contracts\CustomModelInterface.php

<?php namespace App\Contracts;

interface CustomModelInterface {
    public function get();
}

App\Repositories\CustomModelRepository.php

<?php namespace App\Repositories;

use App\Contracts\CustomModelInterface;
use App\Models\CustomModel;

class CustomModelRepository implements CustomModelInterface {

    private $Model;

    public function __construct(CustomModel $model) {
        $this->Model = $model;
    }

    public function get() {
        return 'result';
    }
}

App\Services\MyService.php(在控制器和存储库之间保留业务逻辑/层)

<?php namespace App\Services;

use App\Contracts\CustomModelInterface;

class MyService {

    private $Model;

    public function __construct(CustomModelInterface $customModel) {
        $this->Model= $customModel;
    }

    public function getAll() {
        return $this->Model->get();
    }
}

App\Providers\AppRepositoryProvider.php

<?php namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class AppRepositoryProvider extends ServiceProvider {

    public function boot() {}

    public function register() {
        $models = array(
            'CustomModel'
        );

        foreach ($models as $idx => $model) {
            $this->app->bind("App\Contracts\{$model}Interface", "App\Repositories\{$model}Repository");
        }
    }
}

我的控制器看起来像:

<?php namespace App\Http\Controllers;

use App\Services\MyService;

class SuperController extends Controller {

    private $My;

    public function __construct(MyService $myService) {
        $this->My = $myService;
    }

    public function getDetails() {
        return $this->My->getAll();
    }
}

composer.json

"autoload": {
        "classmap": [
            "database"
        ],
        "psr-4": {
            "App\": "app/",
            "App\Models\": "app/Models/",
            "App\Contracts\": "app/Contracts/",
            "App\Repositories\": "app/Repositories/"
        }
    },

App\Services\MyService.php 上,您正在通过依赖注入传递该接口,它试图实例化该接口 -

public function __construct(CustomModelInterface $customModel) {
    $this->Model= $customModel;
}

这是错误的。

尝试在 class 中实现它 - class MyService implements CustomModelInterface { 并使用该接口的功能,如 -

$this->get();

或者您正在使用它 - class CustomModelRepository implements CustomModelInterface {

所以如果你这样做 -

public function __construct(CustomModelRepository $customModel) {
    $this->Model= $customModel;
}

然后你也可以访问接口方法。

我认为这里的问题是您没有将 App\Contracts\CustomModelInterface 绑定到任何东西,因此 Laravel 尝试创建接口实例。

App\Providers\AppRepositoryProvider.php你只有:

$models = array(
            'Model'
        );

但是你也应该在这个数组中有 CustomModel,所以它应该是这样的:

$models = array(
            'Model',
            'CustomModel',
        );

谢谢大家,但问题出在我的 AppRepositoryProvider 中。因为它是绑定异常,所以显然问题出在绑定 :)

正确的文件是:

<?php namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class AppRepositoryProvider extends ServiceProvider {

    public function boot() {}

    public function register() {
        $models = array(
            'CustomModel',
            'CustomModel2',
            'CustomModel3'
        );

        foreach ($models as $model) {
            $this->app->bind("App\Contracts\{$model}Interface", "App\Repositories\{$model}Repository");
        }
    }
}

请注意,我使用的是 "App\Contracts\{$model}Interface"(未转义“{”符号)并且它生成正确的字符串 App\Contracts\CustomModelInterface 而不是 App\Contracts\{$model}Interface(意外转义)。

每次创建新的 repository/contract 对时,我都会确保执行以下操作:

  1. 检查服务提供者中使用的 类(copy/paste 命名空间)
  2. 在 config/app 中注册新绑定。php
  3. php artisan 优化

许多小时无用的调试使我得出了这个简短的清单。

请注意,这也可能是由于 class 上的 _constructor 被声明为私有,或者被阻止... 如果它不能调用构造函数,绑定将失败

您做的最后一件事是使用您绑定到存储库的接口。

设置并尝试 运行 您的 laravel 应用程序以确保没有错误。

就我而言,我的存储库和界面不匹配。

interface UserRepositoryInterface{
  public function get($userId); 
}

class UserRepository implements UserRepositoryInterface{
  public function get(int $userId);
}

如您所见,接口 get 方法不包含类型提示,但 UserRepository class' get 方法有类型提示。

如果您立即开始使用您的界面绑定,您将不会收到此错误。

对于我来说,我忘记绑定了 app->providers->RepositoryServiceProvider 在 register 方法中这样的存储库

public function register()
{
    $this->app->bind(
        \App\Play\Contracts\PatientRepository::class,
        \App\Play\Modules\PatientModule::class
    );
}

确保您的 RepositoryServiceProvider 已在 AppServiceProvider 中注册。

public function register()
{   
    $this->app->register(RepositoryServiceProvider::class);
}

我克服了这个错误运行:

php artisan config:clear
php artisan clear-compiled
php artisan optimize
php artisan config:cache

相关:

我刚刚遇到了类似的问题,错误的原因是我在服务提供商 class 中将 $defer 设置为 true 但我没有实现了所需的 provides() 方法。

如果您将 class 的创建推迟到需要时而不是急切地加载它,那么您还需要实施 provides 方法,该方法应该只是 return提供者提供的 classes 数组。在接口的情况下,我认为它应该是接口的名称而不是具体的 class.

例如

public method provides(): array
{
    return [
        MyInterface::class,
    ];
}

当前文档:https://laravel.com/docs/5.5/providers#deferred-providers

我希望这对其他人有帮助。

别担心,伙计们。我有办法解决你的问题。

我有一个例子给你。

Step1: php artisan make:repository Repository/Post //通过添加这个命令你可以创建一个仓库并且eloquent文件

第 2 步:添加该文件后,您必须 add/use 要在其中使用的控制器中的此存储库。

例如:使用App\Repositories\Contracts\PostRepository;

第 3 步:在您的控制器中添加该存储库后,如果您将 运行 应用程序,您将收到类似“接口不可实例化”的错误。它来是因为你已经创建了一个 repo 并在控制器中使用,但是 laravel 不知道这个存储库在哪里注册并绑定到哪个 eloquent。从而引发错误。

第 4 步:要解决此错误,您必须将您的存储库与 AppServiceProvider 中的 eloquent 绑定。 例如:

AppServiceProvider.php 文件

<?php
namespace App\Providers;

// **Make sure that your repo file path and eloquent path must be correct.**

use App\Repositories\Contracts\PostRepository;         // **Use your repository here**

use App\Repositories\Eloquent\EloquentPostRepository;  **// Use your eloquent here**

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider {
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register() {

**// And bind your repository and eloquent here. **

        $this->app->bind(PostRepository::class, EloquentPostRepository::class);
    }
}

Step5: 绑定repo和eloquent后你可以在你的controller中使用repo的所有方法。享受......

如果您有任何疑问,请告诉我。

问题已通过在 app/providers/AppServiceProvider 中添加您的存储库来解决 就像下面的例子。

public function register()
{
    $this->app->singleton(UserRepository::class, EloquentUser::class);
 }

别忘了名字space

use Test\Repositories\EloquentUser;
use Test\Repositories\UserRepository;

对我有用

执行这条命令:

composer dump-autoload

此命令将重新映射您的 laravel 自动加载 类 以及所有其他供应商的,我之前遇到过同样的问题,这确实有效,您可以将它与“-o”参数一起使用以进行优化。