Laravel ServiceProvider 的 register() 方法究竟是如何工作的?

5 php functional-programming laravel laravel-5 laravel-5.3

我对PHPLaravel 还很陌生。我正在按照本教程向我的 Laravel 应用程序中的页面添加reCAPTCHA支持:

http://tutsnare.com/how-to-use-captcha-in-laravel-5/

无论如何,我的怀疑与验证码无关,而是与上一教程的内容有关:

如您所见,添加此服务提供者:

'providers' => [
  Anhskohbo\NoCaptcha\NoCaptchaServiceProvider::class,
],
Run Code Online (Sandbox Code Playgroud)

据我了解阅读官方文档:https : //laravel.com/docs/5.4/providers

一个的ServiceProvider是登记在其启动时使用我的应用程序“组件”的东西。

但这究竟是什么意思?

我试图了解它研究以前的NoCaptchaServiceProvider类并将其与文档进行比较。

所以这是它的代码:

<?php

namespace Anhskohbo\NoCaptcha;

use Illuminate\Support\ServiceProvider;

class NoCaptchaServiceProvider extends ServiceProvider
{
    /**
     * Indicates if loading of the provider is deferred.
     *
     * @var bool
     */
    protected $defer = false;

    /**
     * Bootstrap the application events.
     */
    public function boot()
    {
        $app = $this->app;

        $this->bootConfig();

        $app['validator']->extend('captcha', function ($attribute, $value) use ($app) {
            return $app['captcha']->verifyResponse($value, $app['request']->getClientIp());
        });

        if ($app->bound('form')) {
            $app['form']->macro('captcha', function ($attributes = []) use ($app) {
                return $app['captcha']->display($attributes, $app->getLocale());
            });
        }
    }

    /**
     * Booting configure.
     */
    protected function bootConfig()
    {
        $path = __DIR__.'/config/captcha.php';

        $this->mergeConfigFrom($path, 'captcha');

        if (function_exists('config_path')) {
            $this->publishes([$path => config_path('captcha.php')]);
        }
    }

    /**
     * Register the service provider.
     */
    public function register()
    {
        $this->app->singleton('captcha', function ($app) {
            return new NoCaptcha(
                $app['config']['captcha.secret'],
                $app['config']['captcha.sitekey']
            );
        });
    }

    /**
     * Get the services provided by the provider.
     *
     * @return array
     */
    public function provides()
    {
        return ['captcha'];
    }
}
Run Code Online (Sandbox Code Playgroud)

它包含了:

1) register()方法:

public function register()
{
    $this->app->singleton('captcha', function ($app) {
        return new NoCaptcha(
            $app['config']['captcha.secret'],
            $app['config']['captcha.sitekey']
        );
    });
}
Run Code Online (Sandbox Code Playgroud)

它只将东西绑定到服务容器中。在这种情况下,它需要存储到.env文件中的2 个值。这些值包含 re-CAPTCHA 字符串。

我的疑问是:在应用程序启动时 Laravel 调用register()方法,但到底发生了什么?。

register()方法的这一部分是什么意思?

$this->app->singleton('captcha', function ($app) {
        return new NoCaptcha(
            $app['config']['captcha.secret'],
            $app['config']['captcha.sitekey']
        );
    });
Run Code Online (Sandbox Code Playgroud)
  • 谁是$this?我认为它是NoCaptchaServiceProvider实例(但我不太确定),是它还是我遗漏了什么?

  • $this->app是什么意思?app 是方法还是属性?

  • 什么意思$this->app->singleton('captcha'.....}); 我认为它就像一个工厂实现了某个东西的单个实例......但是到底在构建什么?它是 **NoCaptcha实例吗?

  • 我认为之前单例构建的逻辑是由内部函数实现的:

     function ($app) {
         return new NoCaptcha(
            $app['config']['captcha.secret'],
            $app['config']['captcha.sitekey']
     );
    
    Run Code Online (Sandbox Code Playgroud)

在这里我有两个疑问:

第一个是:谁将$app传递给这个函数?它是否类似于稍后将填充的空变量\对象?还是以某种方式注入?

这个函数好像是创建单例的逻辑。因为它放在里面:

singleton('captcha', function ($app) {
        return new NoCaptcha(
            $app['config']['captcha.secret'],
            $app['config']['captcha.sitekey']
        );
    });
Run Code Online (Sandbox Code Playgroud)

那是什么意思呢?这意味着当调用singleton()方法时,会执行返回新NoCaptcha对象的这个函数,它代表了我的单例创建逻辑?

所以这意味着 PHP 以某种方式实现了函数式编程范式

Mel*_*ans 1

$this指的是 NoCaptchaServiceProvider。

NoCaptchaServiceProvider 扩展了服务提供者。它具有属性$app ,它是\Illuminate\Contracts\Foundation\Application又名 Laravel 应用程序的实例。

创建新的服务提供者时,Laravel 会将应用程序实例注入到服务提供者的构造函数中:

public function __construct($app)
{
    $this->app = $app;
}
Run Code Online (Sandbox Code Playgroud)

因此,$this->app您正在检索laravel 应用程序实例

应用程序实例扩展了Container类,该类具有singleton()方法。它只是在容器中注册一个共享绑定。

public function singleton($abstract, $concrete = null)
{
    $this->bind($abstract, $concrete, true);
}
Run Code Online (Sandbox Code Playgroud)

编辑:请注意,这些名称空间指的是合同,而不是实际的类。

服务容器的作用是将接口绑定到给定的实现。契约(或接口)只是告诉类应该实现哪些方法。

例如:我们有 UserRepository,它有 UserRepositoryContract,它告诉某个实现需要具有 all() 和 find() 函数。我们将该 Contract 绑定到 EloquentUserRepository,它只是一个实现这些方法并使用 Eloquent 返回 all() 和 find() 的类。

现在我们唯一需要做的就是设置绑定并使用 UserRepositoryContract 作为实例而不是 EloquentUserRepository。

如果我们以后想使用 Redis,我们只需要创建一个实现相同方法的 RedisUserRepository 类,更改容器中的绑定即可。现在所有 UserRepositoryContract 实例都将使用 Redis 而不是 Eloquent。