- 容器
    - 通俗一点理解容器，我们用PHP中唯一的数据结构数组来做比方。
    - 你可以直接把容器理解为一个数组
    - 数组中的key是一个字符串，作为容器中类实例的标识，方便使用这个标识来调用类的实例
    - 数组中的value就是一个一个类的实例
    - 容器就是存储具有key-value数据结构的，用于存储标识和类实例的一个大集合
    - tp6中，默认在容器中添加了很多的类实例，手册中的[系统内置绑定到容器中的类库包括]的表格中说明了标识和系统类库对应的关系

- 依赖注入
    - 在容器中存入了很多key-value形式的类实例，就可以实现依赖注入。
    - 比如在控制器的某个方法中，使用依赖注入的方式，参数设置一个类，其实这个类在框架进行初始化时，就已经放在容器中了
    - 如果容器中不存在，容器也可以使用composer的类自动加载机制，实时的将类注入进入容器

- 服务
    - 平时在编写程序的时候，我们会写很多服务，比如权限验证，用户信息，支付，手机短信，邮件等等
    - 在tp6之前，我们一般就是写一个一个的类，需要用到的时候就new一下，得到服务类的实例，然后调用服务类的方法
    - 现在tp6使用容器来管理所有的类，当服务类需要使用依赖注入的方式调用时，就需要把服务类注册到容器中
    - tp6就提供了一个配置文件，service.php，写上哪些类需要注册到容器中
    - 注册到容器中的类还可以设置一个标识，那就使用服务类的register方法，或者bind方法
    - 服务不推荐使用，因为php本身语言的问题，容器的初始化是每次请求都会执行的，意味着，每次请求都会实例化所有服务类并注册进容器。服务越多，初始化消耗越大
    
- 门面
    - 门面为容器中的动态类提供了一个静态调用接口，相比于传统的静态方法调用，带来了更好的可测试性和扩展性，你可以为任何的非静态类库定义一个facade类。

laytp里面的服务，其实就是用了tp6的门面，一般由两个文件组成
- 服务具体实现者 这个类无需继承任何基类，只需要实现服务的具体方法
- 服务门面
    - 编写服务门面的原因要谈到如何调用服务
        - 第一种：使用new关键字，创建一个服务具体实现者的类实例，就可以调用服务的方法，这种方法比较通用，但是需要多一行new的代码，而且服务本身还要考虑是否需要实现单例
        - 第二种，使用依赖注入。在控制器层可以使用此方法，调用起来也很方便，但是中间件中，不能使用依赖注入
        - 第三种，编写服务门面类，可以直接使用静态方法调用服务实现者的具体实现方法。此方式代码编写方便，中间件中也可以使用，而且服务门面基类实现了单例
            - 唯一要注意的是，服务门面类需要写好注释，PHPStorm编辑器的代码跟踪才能跟踪到门面类里面来，然后就可以在门面的getFacadeClass方法中继续跟踪服务的具体实现者类
- 服务的目录 /app/service
- 命名规范，以ServiceFacade结尾的就是服务门面

- 服务提供者，文件名和类名一般以Service结尾
- 举例：
    - tp6的验证码就是使用的服务提供者来提供全局调用的
    - vendor/topthink/think-captcha/src/CaptchaService.php
    - 提供者仅需实现服务注册方法，如果服务需要做一些其他操作，可以使用服务启动方法进行操作。
    - 在提供者中，服务启动方法，可以进行路由注册、验证器扩展标识,
    - 服务提供者的用处
        - 提供者实现了服务注册方法，就能进行依赖注入的方式调用服务
        - 提供者的启动方法，服务在调用之前，就会执行的一些程序