简单理解Laravel的核心概念----服务容器、服务提供者、契约

在写之前,我要吐槽一番,laravel的官方文档写的是真恶心,上文不接下文,看的人头皮发麻。
先来说说laravel中的几个核心概念

服务容器

Laravel 服务容器是一个用于管理类依赖和执行依赖注入的强大工具。依赖注入听上去很花哨,其实质是通过构造函数或者某些情况下通过「setter」方法将类依赖注入到类中。

简单的说服务容器就是管理类的依赖和执行依赖注入的工具,这是官方文档上说的。
但是我的理解更偏向于:

一段生命周期所抽象的一个对象

很难理解,打个比方,在一次请求中,你可能会用到很多服务,比如路由,队列,中间件,自定义服务等等。那么如何这么多的服务,如果不能妥善管理,势必会造成各种混乱,这是你不希望看到的,于是你想出了一个办法,用一个篮子,来乘放这些服务,然后使用的时候从篮子中拿就行了。

说到服务容器,就需要说服务容器的两个重要概念IOC(控制反转)DI(依赖注入)
这两个概念并不是laravel中特有的。目的是为了降低软件开发的复杂度;提升模块低耦合、高内聚的一种设计模式

  • 控制反转:容器控制应用程序,由容器反向的向应用程序注入应用程序所需要的外部资源;
  • 依赖注入:应用程序依赖容器创建并注入它所需要的外部资源。

好的,我们知道了控制反转的作用就是实现模块或对象的解耦,通过借助第三方将具有依赖的模块或对象进行解耦,而这个第三方,就是IOC容器
在这里插入图片描述
引入了IoC容器后,对象A、B、C、D之间没有了依赖关系,全体齿轮转动的控制权交给IoC容器。这时候齿轮转动控制权不属于任何对象,而属于IoC容器,所以控制权反转了,从某个对象转到了IoC容器。
在这里插入图片描述
而对于依赖注入,其实首先要明白依赖就是一种关系。如果在类A中创建了类B的实例,就可以说A依赖于B。那么直接在需要依赖的类中声明被依赖的类的实例的方法,会出现下面问题:

  • 如果需要修改类B的创建方式,那么需要修改类A中对B的声明代码
  • 如果想测试不同B对象对A的影响很困难,因为B的初始化被写死在了A的构造函数中
  • 如果要对类B的实例进行调试时,就必须在类A中对类B的实例进行测试,增加了测试难度和复杂度

如果将类B实例作为类A构造器参数进行传入,在调用A的构造器前,B实例已经初始化好了,像这种不是自己主动初始化依赖,而是通过外部传入依赖对象的方式,就是依赖注入

解释完IOC和DI的概念,我们在回想一下刚刚将服务放在篮子中的例子,那么现在就有两个问题了:

  • 如何将服务放在篮子里?
  • 需要某个服务的时候,如果从篮子中拿出来?

这就是laravel中服务容器的两个基本作用:

  • 服务绑定
  • 服务解析

对于具体的绑定/解析方法,官方文档上已经说的很详细了,这里就不举例了,还是对于概念的理解。

服务绑定

一个类要被容器提取,首先要先注册到这个容器。laravel叫这个容器为服务容器,那么我们需要某个服务,就得先注册、绑定这个服务到容器中,那么提供服务并绑定服务到容器的东西,就是服务提供者了。

注:如果一个类没有基于任何接口那么就没有必要将其绑定到容器。容器并不需要被告知如何构建对象,因为它会使用PHP的反射服务自动解析出具体的对象。

服务解析

注册、绑定服务后,就可以根据需要从IOC容器中提取出对应的服务了。就是一个“拿出来”的过程。同样的,具体方法可以自行查看官方文档。

服务提供者

由服务绑定,我们引出了laravel的另外一个核心概念----服务提供者。我们知道,服务容器是“乘放”服务的地方,而服务提供者就是我们将服务放到服务容器的地方。简单说服务提供者就是把服务注册、绑定到容器上的地方。根据官方文档,就是:

服务提供者是Laravel应用启动的中心,你自己的应用以及所有Laravel的核心服务都是通过服务提供者启动。当然启动这些服务,需要加载注册服务,包括注册服务容器绑定、事件监听器、中间件甚至路由。服务提供者是应用配置的中心。

所有的服务提供者都有一个共同的父类Illuminate\Support\ServiceProvider类,这是一个抽象类,要求所有的服务提供者至少需要实现一个register方法,在这个方法中应该只绑定内容到服务容器。

注:永远不要在register方法中尝试在其中注册任何的事件监听,路由或者其它功能。因为我们可能使用了还未注册的服务,从而导致异常。

如何理解这句话的含义呢?

如果有了解过服务容器,就会知道在「绑定」操作仅仅是建立起接口和实现的对应关系,此时并不会创建具体的实例,即不会存在真实的依赖关系。直到某个服务真的被用到时才会从「服务容器」中解析出来,而解析的过程发生在所有服务「注册」完成之后。
一旦我们尝试在 register 注册阶段使用某些未被加载的服务依赖,即这个服务目前还没有被注册所以不可用。
我们可以随意打开一个服务提供者看看:

namespace Illuminate\Cache;

use Illuminate\Support\ServiceProvider;
use Illuminate\Contracts\Support\DeferrableProvider;

class CacheServiceProvider extends ServiceProvider implements DeferrableProvider
{
    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton('cache', function ($app) {
            return new CacheManager($app);
        });

        $this->app->singleton('cache.store', function ($app) {
            return $app['cache']->driver();
        });

        $this->app->singleton('memcached.connector', function () {
            return new MemcachedConnector;
        });
    }

    /**
     * Get the services provided by the provider.
     *
     * @return array
     */
    public function provides()
    {
        return [
            'cache', 'cache.store', 'memcached.connector',
        ];
    }
}

可以看到,在register中只是完成了三个简单的注册。

OK,通过register,我们将服务可以注册绑定到服务容器中,那么当所有的服务都被注册之后,我们需要使用某些服务时,应该在哪里使用呢?服务提供者模版提供了一个boot方法。

boot方法在所有服务提供者被注册以后才会被调用,这就是说我们可以在其中访问框架已注册的所有其它服务。

boot方法在register方法之后调用,这就意味着我们无需在注入某个实例的时候, 它还没有绑定或者实例化。
boot中一般完成启动相应的服务的工作,比如需要处理依赖关系的业务逻辑时,就可以将这些业务逻辑放在boot当中,或者是注册事件监听器,引入路由等你能想到的业务逻辑。
声明完成服务提供者后,添加到config/app.php中的providers数组中进行注册,而在providers数组中默认的注册了laravel中所有的核心服务,这些提供者启动了laravel的核心组件,如邮件,队列,缓存等。

Facades

Facades,我们可以叫做门面,其实就是一组静态接口或者代理,能让开发者简单的访问绑定到容器中的各种服务。

Facades 为应用程序的 服务容器 中可用的类提供了一个「静态」接口。Laravel 本身附带许多的 facades,甚至你可能在不知情的状况下已经在使用他们!Laravel 「facades」作为在服务容器内基类的「静态代理」,拥有简洁、易表达的语法优点,同时维持着比传统静态方法更高的可测试性和灵活性。

举个例子,我们熟知的Route,其实就是一个Facades,它其实就是Illuminate\Support\Facades\Route类的别名,这个facades类代理的是注册到服务容器中的router服务,所以通过Route类就可以很方便的使用router服务中的各种服务,而其中的服务解析完全是进行自动的隐式解析的。至于怎么解析,我们之后会看一看源码,了解一下其流程。

'Route' => Illuminate\Support\Facades\Route::class,

由此,我们可以理解Facade和服务提供者是紧密配合的,所以如果以后自己写Laravel自定义服务时除了通过组件的Service Provider将服务注册进服务容器,还可以在组件中提供一个Facade让应用程序能够方便的访问你写的自定义服务。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值