【问题标题】:Laravel 5 - Interface is not instantiableLaravel 5 - 接口不可实例化
【发布时间】:2015-04-17 04:04:03
【问题描述】:

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

我在 Laravel 5 中遇到异常

BindingResolutionException in Container.php line 785:
Target [App\Contracts\CustomModelInterface] is not instantiable.

我做了什么没有成功:

  • app.php提供者中注册App\Providers\AppRepositoryProvider
  • php artisan clear-compiled
  • 如果我在 MyService 中替换存储库上的接口,一切正常,但我觉得这是错误的(应该由 IoC 容器处理吗?)。

结构:

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/"
        }
    },

【问题讨论】:

  • 今天我发现了这个问题,因为我收到了同样的错误信息。就我而言,在我的 ServiceProvider 中,我有属性 $defer = true; 这会导致同样的错误。如果您遇到同样的问题,只需删除该属性即可。

标签: php laravel repository-pattern laravel-5 laravel-ioc


【解决方案1】:

谢谢大家,但问题出在我的 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(意外转义)。

【讨论】:

  • 如果我没记错的话,你现在只是跳过了interface,因为现在你已经使用了绑定之后,每次调用interface都会解析repository的一个对象。 .. 而不是界面,您没有按照应有的方式使用SoC 设计模式...您的interface 文件现在没用了。如果我错了,请纠正我。
  • 你能解释一下为什么你使用App\Contracts\\{$model}Interface而不使用App\Contracts\{$model}Interface ,双反斜杠是什么意思?
  • @tdycss 第一个反斜杠是命名空间的一部分,第二个反斜杠用于转义 { - 如果没有转义,您最终会在生成的命名空间中得到 {},这在这个案例。另请参阅答案中代码示例下的注释。希望有帮助(:
【解决方案2】:

每次创建新的存储库/合约对时,我都会确保执行以下操作:

  1. 检查服务提供者中使用的类(复制/粘贴命名空间)
  2. 在 config/app.php 中注册一个新的绑定
  3. php 工匠优化

数小时无用的调试使我得到了这份简短的清单。

【讨论】:

  • 我忘了#2,救了我
  • 我也错过了#2!我从 Laravel 4 升级到 5,需要在 config/app.php 中显式注册我的自定义提供程序以及默认服务提供程序。
  • 我必须运行 php artisan config:cache
【解决方案3】:

对我来说,我忘了绑定app-&gt;providers-&gt;RepositoryServiceProvider 注册方法中这样的存储库

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);
}

【讨论】:

  • 这是我的错误。谢谢!
  • 听起来不错!格拉西亚斯
  • 出于某种原因,即使我已将文件添加到 config/app.php,这也解决了我的问题。我在 register() 中注册了提供者,运行 config:cache,将 register() 中的行去掉,后续缓存成功。
【解决方案4】:

我在运行时克服了这个错误:

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

相关:

Target is not instantiable. Laravel 5 - App binding service provider

【讨论】:

  • 很好..至少它做了一些事情。
【解决方案5】:

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

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

不要忘记命名空间

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

它对我有用

【讨论】:

    【解决方案6】:

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

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

    这是错误的。

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

    $this->get();
    

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

    所以如果你这样做 -

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

    那么你也可以访问接口方法。

    【讨论】:

    • 感谢您的快速回复。我不能使用类 MyService 实现 CustomModelInterface 因为 MyService 只是一个可与多个存储库一起使用的服务。问候公共函数 __construct(CustomModelRepository $customModel) { $this->Model= $customModel; } - 这是我一开始想做的,但我觉得它错了......
    • 因为你没有利用界面。如果他必须传递类的真正实现,则必须更改类参数以防万一您想提供另一种CustomModel
    • @Sougata Bose,看来你可以帮助我。看看这个:stackoverflow.com/questions/45956810/…
    【解决方案7】:

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

    如果您已将类的创建推迟到需要它而不是急切地加载,那么您还需要实现 provides 方法,该方法应该简单地返回提供者提供的类的数组。对于接口,我认为应该是接口的名称而不是具体的类。

    例如

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

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

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

    【讨论】:

    • 正确。之后也不要忘记运行“composer dump-autoload”。
    【解决方案8】:

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

    【讨论】:

    • 这解决了我使用 Laravel 7 的问题!我不小心声明了protected function _constructor()
    【解决方案9】:

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

    我有一个例子给你。

    Step1: php artisan make:repository Repository/Post //添加这个命令可以创建repository和eloquent文件

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

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

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

    Step4:要解决这个错误,您必须在 AppServiceProvider 中将您的 repo 与您的 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 后,你可以在你的控制器中使用 repo 的所有方法。享受.....

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

    【讨论】:

    • 当然。谢谢你的评论。我将简要介绍一下。
    • 亲爱的迪特,我已经更新了我的答案。如果您有任何疑问,请告诉我。
    • 你是对的。类必须在 appServiceProvider 中注册
    【解决方案10】:

    执行这个命令:

    composer dump-autoload
    

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

    【讨论】:

    • 请在您的答案中添加一些解释,以便其他人可以从中学习
    • 请编辑您的答案以包含所有相关信息
    【解决方案11】:

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

    App\Providers\AppRepositoryProvider.php 你只有:

    $models = array(
                'Model'
            );
    

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

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

    【讨论】:

    • 对不起,这是我的一个问题。你说得对,应该是 CustomModel 而不是 Model。我更新了我的问题以消除混淆。
    • @Marcin Nabiałek,看来你可以帮助我。看看这个:stackoverflow.com/questions/45956810/…
    【解决方案12】:

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

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

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

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

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

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

    【讨论】:

      猜你喜欢
      • 2013-02-20
      • 2015-06-07
      • 2023-03-05
      • 2015-03-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多