为什么赢了';这不是Laravel 5.4服务提供商注册吗?

为什么赢了';这不是Laravel 5.4服务提供商注册吗?,laravel,laravel-5.3,Laravel,Laravel 5.3,我正在尝试用新的Laravel 5.4做一个hello world服务提供商 我已创建以下服务提供商文件: //File: app/TestProvider/TestServiceProvider.php namespace App\TestProvider; use Illuminate\Support\ServiceProvider; class TestServiceProvider extends ServiceProvider { /** * Register

我正在尝试用新的Laravel 5.4做一个hello world服务提供商

我已创建以下服务提供商文件:

//File: app/TestProvider/TestServiceProvider.php

namespace App\TestProvider;

use Illuminate\Support\ServiceProvider;

class TestServiceProvider extends ServiceProvider
{
    /**
     * Register bindings in the container.
     *
     * @return void
     */
    public function register()
    {       
        $this->app->bind('Test', function ($app) {
            return new Test();
        });
    }
}
我在同一命名空间下创建了一个简单类:

//File: app/TestProvider/Test.php

namespace App\TestProvider;

class Test 
{
    /**
     * Register bindings in the container.
     *
     * @return void
     */
    public function helloWorld()
    {       
        echo "hello world";
    }
}
问题是,这不是注册。寄存器方法的执行方式与我在“bind”方法之前放置一个断路器时相同,它执行:

public function register()
{       
    dd("BREAKER");
    $this->app->bind('Test', function ($app) {
        return new Test();
    });
}
因此,这将输出预期的“断路器”。然而,如果我将断路器置于关闭状态,则不会发生任何事情,这表明出于某种原因,“绑定”方法没有被执行

有什么想法吗

编辑:

只是一些进一步的信息:我知道测试类已注册,并且位于正确的命名空间中,正如我所能做的:

dd(new Test());
在注册方法中,它会按预期输出资源id。

尝试:

$this->app->bind(Test::class, function ($app) {
    return new Test();
});

传递给
bind()
方法的闭包在您实际尝试解析绑定的别名之前不会执行

因此,如果在闭包内执行
dd('breaker')
,则在解决
Test
之前,不会执行此操作(无论您首选的解决方法是什么):

服务提供者:

// bind the closure to the 'Test' alias
public function register()
{       
    $this->app->bind('Test', function ($app) {
        dd("BREAKER");
        return new Test();
    });
}
解析测试别名的代码:

// different ways of resolving the alias out of the container.
// any of these will execute the bound closure.
$test = resolve('Test');
$test = app('Test');
$test = app()->make('Test');
$test = \App::make('Test');
解释 提供的闭包仅在解析绑定时运行。这就是为什么它是一个闭包,它可以保存在服务容器中,并在程序运行时随时解析

解决方案 要查看已解析的绑定,请创建控制器并解析该控制器中的类:

//文件:app/Http/Controllers/TestController.php
名称空间App\Http\Controllers;
//这不是最好的方法,但它很有效。请参阅下面的最佳方式
类TestController扩展控制器{
公共职能指数()
{
return\App::make('Test')->helloWorld();
}
}
当然,不要忘记注册路线:

//文件:routes/web.php
路由::获取('/','TestController@index');
当您点击主页时,绑定将解决

然而,正如我所说,这不是最好的方法,所以在这里我准备了一个更好的方法。更改注册绑定的方式:

//文件:app/Providers/TestProvider.php
名称空间App\TestProvider;
使用Illumb\Support\ServiceProvider;
使用App\TestProvider\Test;
//更好的方法
类TestServiceProvider扩展了ServiceProvider
{
/**
*在容器中注册绑定。
*
*@返回无效
*/
公共职能登记册()
{
//注意:我们绑定了准确完整的类名!
$this->app->bind(测试::类,函数($app){
返回新测试();
});
}
}
在此之后,更改控制器,使其如下所示:

namespace-App\Http\Controllers;
使用App\TestProvider\Test;
类TestController扩展控制器{
/**
*@var Test$Test
*/
私人测试;
//让Laravel解决对构建类的依赖
公共函数构造(Test$Test)
{
$this->test=$test;
}
公共职能指数()
{
返回$this->test->helloWorld();
}
}
你会看到完全相同的事情发生,但它看起来更优雅,避免冲突

细节 Laravel只提供了服务容器的高级概述,这无助于了解它在内部是如何工作的。最好的方法是查看调用堆栈

当您这样做时,您会发现Laravel在服务容器中注册了项目中的每个类。这意味着无论您是否创建服务提供者,该类都将位于容器中。到底是怎么回事

运行
php artisan optimize
时,Laravel将创建包含项目所有类的数组的文件。运行应用程序时,在注册了服务提供商提供的所有内容后,Laravel将注册该文件中的其余类

这意味着在您的情况下,如果您没有专门注册测试类,它仍然是可以解决的。基本上,您只需要注册需要解析某些特定指令的类

那么,Laravel如何解决依赖关系呢

  • 当您运行
    \App::make(Test::class)
    或通过构造函数中的类型暗示(我的解决方案中的“更好的方法”)注入依赖项时,Laravel会在绑定中查找该依赖项
  • 当它找到依赖项时,它会解析与其关联的闭包或直接解析类的构造函数
  • 当它直接解析构造函数时,它会在构造函数参数中查找类型提示,并递归解析所有参数,直到没有其他需要解析的参数为止
  • 然后返回已解析的类
  • 当然,要记住,Laravel要分析类的构造函数,首先需要通过服务容器来解决。您不能只调用
    $test=newtest()并期望拉威尔完成所有的魔法:)

    结论 这是对Laravel服务容器的快速概述。当然,你学习它的最好方法是自己研究资料来源。它非常优雅,充分利用了PHP的功能


    我真的希望这能为您提供一些关于服务容器的信息,并在将来对您有所帮助:)

    您在哪里使用该类?也发布该部分的代码。这并不是对问题的真正回答,但对于任何未来的谷歌用户来说:确保您试图绑定的类的名称空间正确,并且在必要时以斜杠开头。i、 例如,
    $this->app->bind(\Fully\Qualified\Name::class…
    ,而不是
    $this->app->bind(Fully\Qualified\Name::class…
    没什么不幸的。但是您需要在u构造方法中编写回音“Hello World”,而不是helloWorld(),但它没有输出任何内容,因为它没有执行闭包,只是绑定。您可以检查Laravel的本机AuthServiceProvider的寄存器,然后