简体   繁体   English

Laravel 5 - 接口不可实例化

[英]Laravel 5 - Interface is not instantiable

I know that this question was asked so many times, but none of answers helped me.我知道这个问题被问了很多次,但没有一个答案对我有帮助。

I'm getting exception in Laravel 5我在 Laravel 5 中遇到异常

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

What I've done without success:我所做的没有成功:

  • Register App\Providers\AppRepositoryProvider in app.php providersapp.php providers 中注册App\Providers\AppRepositoryProvider
  • php artisan clear-compiled
  • Everything works if I replace interfaces on repositories in MyService, but I feel that it's wrong (should it be handled by IoC container?).如果我在 MyService 中替换存储库上的接口,一切正常,但我觉得这是错误的(它应该由 IoC 容器处理吗?)。

Structure:结构:

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

App\Contracts\CustomModelInterface.php应用\合同\CustomModelInterface.php

<?php namespace App\Contracts;

interface CustomModelInterface {
    public function get();
}

App\Repositories\CustomModelRepository.php 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 (Keep business logic / layer between controller and repositories) App\Services\MyService.php(保持controller和存储库之间的业务逻辑/层)

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

My controller looks like:我的 controller 看起来像:

<?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作曲家.json

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

Thank you everyone, but problem was in my AppRepositoryProvider.谢谢大家,但问题出在我的 AppRepositoryProvider 中。 As it's binding exception, then obviously the problem was with binding :)由于它是绑定异常,那么显然问题出在绑定上:)

Correct file is:正确的文件是:

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

Note, that I'm using "App\\Contracts\\\\{$model}Interface" (not escaping "{" symbol) and it generate correct string App\\Contracts\\CustomModelInterface instead of App\\Contracts\\{$model}Interface (with unexpected escaping).请注意,我使用的是"App\\Contracts\\\\{$model}Interface" (不转义“{”符号)并且它生成正确的字符串App\\Contracts\\CustomModelInterface而不是App\\Contracts\\{$model}Interface (与出乎意料的逃跑)。

Every time I create a new repository/contract pair I make sure I do the following:每次创建新的存储库/合约对时,我都会确保执行以下操作:

  1. check the classes used in the service provider (copy/paste the namespaces)检查服务提供者中使用的类(复制/粘贴命名空间)
  2. register a new binding in config/app.php在 config/app.php 中注册一个新的绑定
  3. php artisan optimize php工匠优化

Many hours of useless debugging led me to this short checklist.许多小时的无用调试使我找到了这个简短的清单。

For me, I forgot to bind in app->providers->RepositoryServiceProvider the repository like this in the register method对我来说,我忘了在app->providers->RepositoryServiceProvider中在 register 方法中绑定这样的存储库

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

Make sure your RepositoryServiceProvide r is registered in AppServiceProvider .确保您的RepositoryServiceProvide已在AppServiceProvider注册。

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

I got past this error running:我克服了这个错误运行:

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

Related to:相关:

Target is not instantiable. 目标不可实例化。 Laravel 5 - App binding service provider Laravel 5 - 应用绑定服务提供者

The problem is solved by adding your repository in app/providers/AppServiceProvider like the example below.通过在 app/providers/AppServiceProvider 中添加您的存储库来解决该问题,如下例所示。

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

Dont forget the name space不要忘记命名空间

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

It worked for me它对我有用

On App\\Services\\MyService.php you are passing that interface with dependency injection which tries to instantiate that -App\\Services\\MyService.php您正在通过依赖注入传递该接口,该接口试图实例化 -

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

which is wrong.这是错误的。

Try implement that in that class - class MyService implements CustomModelInterface { and use the function of that interface like -尝试在该类中实现它 - class MyService implements CustomModelInterface {并使用该接口的功能,例如 -

$this->get();

Or you are using it - class CustomModelRepository implements CustomModelInterface {或者你正在使用它 - class CustomModelRepository implements CustomModelInterface {

So if you do -所以如果你这样做——

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

then also you can access the interface methods.然后你也可以访问接口方法。

请注意,这也可能是由于类上的 _constructor 被声明为私有导致的,或者以其他方式被阻塞......如果它无法调用构造函数,则绑定将失败

I've just experienced an issue similar to this and the cause of my error was that I had set $defer to true in the service provider class but I had not implemented the required provides() method.我刚刚遇到了一个类似的问题,我的错误的原因是我在服务提供者类中将$defer设置$defer true ,但我没有实现所需的provides()方法。

If you have deferred the creation of your class until it is need rather than it being loaded eagerly, then you need to also implement the provides method which should simply return an array of the classes that the provider provides.如果您推迟了类的创建,直到需要它而不是急切地加载它,那么您还需要实现provides方法,该方法应该简单地返回提供者提供的类的数组。 In the case of an interface, I believe it should be the name of the interface rather than the concrete class.在接口的情况下,我认为它应该是接口的名称而不是具体的类。

Eg例如

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

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

I hope this helps somebody else.我希望这对其他人有帮助。

Don't worry guys.别担心,伙计们。 I have a solution to your problem.我有一个解决你的问题的方法。

I have an example for you.我有一个例子给你。

Step1: php artisan make:repository Repository/Post //By adding this command you can create a repository and eloquent files Step1: php artisan make:repository Repository/Post //添加这个命令就可以创建repository和eloquent文件

Step2: After adding that file you have to add/use this repository in the controller in which you want to use.步骤 2:添加该文件后,您必须在要使用的控制器中添加/使用此存储库。

for eg: use App\\Repositories\\Contracts\\PostRepository;例如:使用 App\\Repositories\\Contracts\\PostRepository;

Step3: After adding that repo in your controller if you will run the app you will get an error like " Interface is not instantiable".第 3 步:在您的控制器中添加该 repo 后,如果您将运行该应用程序,您将收到类似“接口不可实例化”的错误消息。 It comes because you have created a repo and used in a controller, but laravel don't know where this repository is register and bind with which eloquent.这是因为你已经创建了一个 repo 并在一个控制器中使用,但是 laravel 不知道这个存储库在哪里注册并绑定到哪个 eloquent。 So that it throws an error.所以它会抛出一个错误。

Step4: To solve this error you have to bind your repo with your eloquent in AppServiceProvider .步骤 4:要解决此错误,您必须将您的 repo 与AppServiceProvider 中的 eloquent 绑定。 Eg:例如:

AppServiceProvider.php file 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: After binding repo and eloquent you can use all method of repo in your controller.第五步:绑定 repo 和 eloquent 后,您可以在控制器中使用所有 repo 方法。 Enjoy.....享受.....

Please let me know if you have any query.如果您有任何疑问,请告诉我。

I think the problem here is that you don't bind App\\Contracts\\CustomModelInterface to anything so Laravel tries to create instance of interface.我认为这里的问题是你没有将App\\Contracts\\CustomModelInterface绑定到任何东西,所以 Laravel 尝试创建接口实例。

In App\\Providers\\AppRepositoryProvider.php you have only:App\\Providers\\AppRepositoryProvider.php你只有:

$models = array(
            'Model'
        );

but you should have in this array CustomModel also, so it should look like this:但是你也应该在这个数组中CustomModel ,所以它应该是这样的:

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

The last thing you do is to use the interface you bound to the repository.您做的最后一件事是使用您绑定到存储库的接口。

Set it up and try running your laravel app to make sure you get no errors.设置它并尝试运行你的 Laravel 应用程序以确保你没有错误。

In my case I had a mismatch between my repository and interface.就我而言,我的存储库和界面不匹配。

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

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

As you can see the interface get method does not include a type hint but the UserRepository class' get method has a type hint.如您所见,接口 get 方法不包含类型提示,但 UserRepository 类的 get 方法具有类型提示。

You won't get this error if you immediately start to use your Interface Binding.如果您立即开始使用接口绑定,则不会出现此错误。

register a new binding in config/app.php在 config/app.php 中注册一个新的绑定

In my case I forgot use App\Repositories\UserRepository in App\Providers\AppRepositoryProvider.php在我的例子中,我忘记了在 App\Providers\AppRepositoryProvider.php 中use App\Repositories\UserRepository UserRepository

intelephense wasn't complaining and the error-message did not give me any clue, but somehow I found out that it's missing and adding this line did the trick intelephense 没有抱怨,错误消息也没有给我任何线索,但不知何故,我发现它不见了,添加这一行就成功了

execute this command :执行这个命令:

composer dump-autoload

this command will remap your laravel autoload classes together with all other vendor's i had same issue before and this did the trick you can use it together with "-o" param for optimization .此命令将重新映射您的 Laravel 自动加载类以及所有其他供应商的我之前遇到过同样的问题,这解决了您可以将它与“-o”参数一起使用以进行优化的技巧。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM