Laravel 4 目标接口不可实例化

Posted

技术标签:

【中文标题】Laravel 4 目标接口不可实例化【英文标题】:Laravel 4 target interface is not instantiable 【发布时间】:2013-02-20 15:01:26 【问题描述】:

这与How to register a namespace in laravel 4 这个问题有关,但我相信我已经解决了这个问题,并且命名空间现在正在工作。

我遇到了一个新问题。我相信错误来自尝试在控制器构造函数中键入提示,并且与使用命名空间和使用 ioc 有关。

BindingResolutionException: Target [App\Models\Interfaces\PostRepositoryInterface] is not instantiable.

在我尝试引入命名空间之前,以下方法运行良好。我可以删除所有命名空间并将接口和存储库放在同一目录中,但想知道如何使命名空间与这种使用 ioc 的方法一起工作。

这里是相关文件。

routes.php

Route::resource('posts', 'PostsController');

PostController.php

<?php
use App\Models\Interfaces\PostRepositoryInterface;
class PostsController extends BaseController 

    public function __construct( PostRepositoryInterface $posts )
    
        $this->posts = $posts; 
    


PostRepositoryInterface.php

<?php namespace App\Models\Interfaces;
interface PostRepositoryInterface 
    public function all();
    public function find($id);
    public function store($data);

EloquentPostRepository.php

<?php namespace App\Models\Repositories;
use App\Models\Interfaces\PostRepositoryInterface;
class EloquentPostRepository implements PostRepositoryInterface 

    public function all()
    
        return Post::all();
            //after above edit it works to this point
            //error: App\Models\Repositories\Post not found
            //because Post is not in this namespace
    

    public function find($id)
    
        return Post::find($id);
    

    public function store($data)
    
        return Post::save($data);
    

你可以看到 composer dump-autoload 完成了它的工作。

作曲家/autoload_classmap.php

return array(
    'App\\Models\\Interfaces\\PostRepositoryInterface' => $baseDir . '/app/models/interfaces/PostRepositoryInterface.php',
    'App\\Models\\Repositories\\EloquentPostRepository' => $baseDir . '/app/models/repositories/EloquentPostRepository.php',

    ....
    )

任何想法我需要改变什么地方或什么地方才能使它与命名空间一起工作,就像没有它们一样?

谢谢

【问题讨论】:

我已经克服了第一个错误。我不知道 App::bind() 是如何工作的,但是将整个命名空间作为字符串传递是有效的。我将更新那部分代码。现在问题出在 EloquentPostRepository 中,因为它是命名空间的,当我尝试调用 Post::all() 时,它会将“Post”放在“Repositories”命名空间中。需要弄清楚如何在命名空间之外调用一个类。 【参考方案1】:

好的,简短的回答:使用 App::bind() 中的完整命名空间来修复第一个错误。 然后在 EloquentPostRepository.php 中,因为它有一个声明的命名空间,它会尝试将任何其他外部类调用视为在同一个命名空间中。添加一个简单的“使用帖子;”让 PHP 知道“Post”不在同一个命名空间(App\Models\Repositories)中。我认为这是因为一旦使用了命名空间,其他类默认具有任何类名的命名空间。我认为重新发布所有已更正并正常工作的代码是最简单的。

routes.php

<?php

App::bind('App\Models\Interfaces\PostRepositoryInterface',  'App\Models\Repositories\EloquentPostRepository');

Route::resource('posts', 'PostsController');

PostController.php

<?php
use App\Models\Interfaces\PostRepositoryInterface;

class PostsController extends BaseController 

    public function __construct(PostRepositoryInterface $posts)
    
        $this->posts = $posts;
    

EloquentPostRepository.php

<?php namespace App\Models\Repositories;
use App\Models\Interfaces\PostRepositoryInterface;
use Post;
class EloquentPostRepository implements PostRepositoryInterface 

    public function all()
    
        return Post::all();
    

    public function find($id)
    
        return Post::find($id);
    

    public function store($data)
    
        return Post::save($data);
    

PostRepositoryInterface.php

<?php namespace App\Models\Interfaces;
interface PostRepositoryInterface 
    public function all();
    public function find($id);
    public function store($data);

Post.php 除了显示它没有声明的命名空间之外,这里没有任何相关性

<?php
class Post extends BaseModel 

    public static $rules = [
        'title' => 'required',
        'body' => 'required',
        'author_id' => 'required|numeric'
    ];

    public static $factory = [
        'title' => 'string',
        'body' => 'text'
    ];

    public function user()
    
        return $this->belongsTo('User', 'author_id');
    


【讨论】:

您不需要在 PostController.php 中添加实现 (EloquentPostRepository)。这样您就可以保持只需在 routes.php. 的绑定中更改一个地方的实现的优势 好收获。不知道为什么我在那里。我删除了它。【参考方案2】:

我知道这个问题已经得到解答,但我想提醒未来的读者,这个“target interface is not instantiable”错误的另一个常见原因是忘记在app/config/app.php 中注册服务提供商。

这仅适用于扩展 ServiceProvider 类的情况,不适用于使用 App::bind() 的情况。

我犯了太多次这个错误,所以没有发布有关它的内容。因此,在您走上上述漫长道路之前,请务必注册这些提供商!

【讨论】:

好点。在提出这个问题时,我不了解服务提供商。很高兴让人们知道这是此错误的另一种情况。 当我将构造函数设为私有时,我遇到了这个错误。更改为 public 解决了问题 另一个问题(我遇到的那个)是在我的命名空间中使用 / 而不是 ``。虽然是一个非常简单的错误,但它是一个 PITA 来调试 我认为值得一提的是,如果您在类名中输入错误,可能会发生此错误。这发生在我使用 App::bind() 时。因此,它还会给你一个Target [interfacename] is not instantiable.,而不是Class 'Classname' not found 另一个注意事项:如果您确实已经注册了服务提供商并且您仍然收到此错误,请记住php artisan config:clear清除你的缓存。 (捂脸)

以上是关于Laravel 4 目标接口不可实例化的主要内容,如果未能解决你的问题,请参考以下文章

“目标 [App\Http\Controllers\Controller] 不可实例化。”

Laravel 依赖注入“不可实例化”

Laravel 自定义类验证器:TranslatorInterface 不可实例化

自定义 laravel 迁移命令“[Illuminate\Database\Migrations\MigrationRepositoryInterface] 不可实例化”

第4条:通过私有构造器强化不可实例化的能力

第4条:通过私有构造器强化不可实例化的能力