二:依赖注入
一:Hyperf 介绍
Hyperf 设计理念

Hyperf常用命令行
(1):查看命令列表
php bin/hyperf.php list
(2):启动命令
php bin/hyperf.php start
(2):查看路由注册状态
php bin/hyperf.php describe:routes
(3):创建控制器
php bin/hyperf.php gen:controller IndexController
(4):创建模型
php bin/hyperf.php gen:model User
二:Hyperf的路由 https://hyperf.wiki/2.2/#/zh-cn/router


一:简单对象注入
(1):通过构造方法注入
假设我们需要在 GoodsController 内调用 GoodsService 类的 getInfoById(string $id) 方法。



注意使用构造函数注入时,调用方也就是 IndexController 必须是由 DI 创建的对象才能完成自动注入(依赖注入的依赖关系都是容器作为第三方调度器,使其各个对象关联起来),而 Controller 默认是由 DI 创建的,所以可以直接使用构造函数注入
当您希望定义一个可选的依赖项时,可以通过给参数定义为 nullable 或将参数的默认值定义为 null,即表示该参数如果在 DI 容器中没有找到或无法创建对应的对象时,不抛出异常而是直接使用 null 来注入。*(该功能仅在 1.1.0 或更高版本可用)*


(2):通过@Inject注解注入
假设我们需要在 ItemController 内调用 ItemService 类的 getInfoById(string $id) 方法。



通过 @Inject 注解注入可作用于 DI 创建的(单例)对象,也可作用于通过 new 关键词创建的对象;
使用 @Inject 注解时需 use Hyperf\Di\Annotation\Inject; 命名空间;
Required 参数
@Inject 注解存在一个 required 参数,默认值为 true,当将该参数定义为 false 时,则表明该成员属性为一个可选依赖,当对应 @var 的对象不存在于 DI 容器或不可创建时,将不会抛出异常而是注入一个 null,如下:


二:抽象对象注入
基于上面的例子,从合理的角度上来说,Controller 面向的不应该直接是一个 UserService服务 类,可能更多的是一个 UserServiceInterface 的接口类,此时我们可以通过 config/autoload/dependencies.php 来绑定对象关系达到目的,我们还是通过代码来解释一下。
定义一个接口类:

在 config/autoload/dependencies.php 内完成关系配置:



三:工厂对象注入
我们假设 MessageService 的实现会更加复杂一些,在创建 MessageService 对象时构造函数还需要传递进来一些非直接注入型的参数,假设我们需要从配置中取得一个值,然后 MessageService 需要根据这个值来决定是否开启缓存模式(顺带一说 Hyperf 提供了更好用的 模型缓存 功能)
通过构造函数注入的参数,应该是一个应用参数,而不是一个动态的跟请求相关的参数,因为所有从DI容器里创建出来的对象都是一个单例,在Hyperf的生命周期里这个单例是进程全局的单例对象,也就是说这个对象有可能被多个请求同时使用的,也就是说我们所有从DI取出来的对象的构造函数,或者成员属性都不应该是与请求相关的动态参数,只能是一个固定的配置,或者从配置文件读取的配置,或者是其它对象的一个依赖;
我们需要创建一个工厂来生成 MessageService 对象:

1:通过工厂类来创建复杂的对象;
2:定义一个工厂类于__invoke()方法内实现对象的创建并返回;
3:make()函数创建短生命周期对象;
其中提供了__invoke()这个方法;这个方法里提供了container这个参数;这个container默认的也就是注入Hyperf的DI容器对象;通过这个对象是可以从Hyperf的DI容器里面取出其它任意的对象;
首先从容器取出配置的一个服务类ContainerInterface,该服务类对应于Hyperf\Contract\ConfigInterface;通过get方法取出对应的配置;
make(MessageService::class, compact('enableCache')); 相当于new一个MessageService这个类并且在MessageService的构造函数中传递参数'enableCache';
compact('enableCache')解释:取当前方法内跟这个字符串同名的变量的值形成key-value这个关系key就是enableCache而value就是enableCache对应的变量的值,这里也就是上面$enableCache的值;
最终返回一个实例化好的MessageService
调整接口类与工厂类的关系;注入的即为由工厂类创建的对象;

这样在注入 UserServiceInterface 的时候容器就会交由 UserServiceFactory 来创建对象了。


在 config/autoload/dependencies.php 调整绑定关系:
![]()
这样在注入 MessageServiceInterface 的时候容器就会交由 MessageServiceFactory 来创建对象了。
当然在该场景中可以通过 @Value 注解来更便捷的注入配置而无需构建工厂类,此仅为举例
短生命周期对象
通过 new 关键词创建的对象毫无疑问的短生命周期的,那么如果希望创建一个短生命周期的对象但又希望使用 构造函数依赖自动注入功能 呢?这时我们可以 通过 make(string $name, array $parameters = []) 函数来创建 $name 对应的的实例,代码示例如下:
$userService = make(UserService::class, ['enableCache' => true]);
注意仅 $name 对应的对象为短生命周期对象,该对象的所有依赖都是通过 get() 方法获取的,即为长生命周期的对象,可理解为该对象是一个浅拷贝的对象
获取容器对象
(1):有些时候我们可能希望去实现一些更动态的需求时,会希望可以直接获取到 容器(Container) 对象,在绝大部分情况下,框架的入口类(比如命令类、控制器、RPC 服务提供者等)都是由 容器(Container) 创建并维护的,也就意味着您所写的绝大部分业务代码都是在 容器(Container) 的管理作用之下的,也就意味着在绝大部分情况下您都可以通过在 构造函数(Constructor) 声明或通过 @Inject 注解注入 Psr\Container\ContainerInterface 接口类都能够获得 Hyperf\Di\Container 容器对象,我们通过代码来演示一下:

(2):在某些更极端动态的情况下,或者非 容器(Container) 的管理作用之下时,想要获取到 容器(Container) 对象还可以通过 \Hyperf\Utils\ApplicationContext::getContaienr() 方法来获得 容器(Container) 对象。
$container = \Hyperf\Utils\ApplicationContext::getContainer();




浙公网安备 33010602011771号