- jwt DateTimeImmutable 报错:
jwt DateTimeImmutable 问题 降低版本到3.3.3解决问题: composer require lcobucci/jwt:3.3.3
- hyperf使用注解的坑,hyperf使用注解会让注解的实例变为单例,
问题1:model产生问题 ***
如果我们注解一个model给变量,当有两个地方会查询数据,第一个查询会是A+B连接查询,第二个是A+B+C连接查询,如果第二个查询有一个参数时C的,执行二后在执行第一个会导致报错,报C中的参数不存在,单位这个实例是单例的,第二个查询的参数不会被清除,
问题二:实例化时如果带参数 ***
如果实例化带参数,第一个实例化带了一个参数,第二个操作时不会重新实例化,这样会导致第二次使用还是第一次的参数,导致出错
问题三:公共属性
在控制器中一个属性被改变,后面再有请求来获取属性时获取到是最新的,不是初始化的,
-
Inject或Value注解不生效
使用了构造函数中注入
Inject
和Value
的功能,以下两种场景,可能会导致注入失效,请注意使用。- 原类没有使用
Inject
或Value
,但父类使用了Inject
或Value
,且原类写了构造函数,同时又没有调用父类构造函数的情况。
这样就会导致原类不会生成代理类,而实例化的时候又调用了自身的构造函数,故没办法执行到父类的构造函数。
所以父类代理类中的方法__handlePropertyHandler
就不会执行,那么Inject
或Value
注解就不会生效。class ParentClass { /** * @Inject * @var Service */ protected $value; } class Origin extends ParentClass { public function __construct() {} }
- 原类没有使用
Inject
或Value
,但Trait
中使用了Inject
或Value
。
这样就会导致原类不会生成代理类,故没办法执行构造函数里的
__handlePropertyHandler
,所以Trait
的Inject
或Value
注解就不会生效。trait OriginTrait { /** * @Inject * @var Service */ protected $value; } class Origin { use OriginTrait; }
- 原类没有使用
基于上述两种情况,可见 原类
是否生成代理类至关重要,所以,如果使用了带有 Inject
或 Value
的 Trait
和 父类
时,给原类添加一个 Inject
,即可解决上述两种情况。
use Hyperf\Contract\StdoutLoggerInterface;
trait OriginTrait {
/**
* @Inject
* @var Service
*/
protected $trait;
}
class ParentClass {
/**
* @Inject
* @var Service
*/
protected $value;
}
class Origin extends ParentClass
{
use OriginTrait;
/**
* @Inject
* @var StdoutLoggerInterface
*/
protected $logger;
}
-
一般建议使用make,而不是new,
使用 make() 方法是为了允许 AOP 的介入,而直接 new 会导致 AOP 无法正常介入流程 2.0以后不会有这个问题,这个可以参考https://www.hyperf.wiki/2.1/#/zh-cn/changelog?id=v20-2020-06-22
通过 new 关键词创建的对象毫无疑问的短生命周期的,那么如果希望创建一个短生命周期的对象但又希望使用 构造函数依赖自动注入功能 呢?这时我们可以通过 make(string $name, array $parameters = [])
-
注意事项
注意事项
容器仅管理长生命周期的对象
换种方式理解就是容器内管理的对象都是单例,这样的设计对于长生命周期的应用来说会更加的高效,减少了大量无意义的对象创建和销毁,这样的设计也就意味着所有需要交由 DI 容器管理的对象均不能包含
状态
值。
状态
可直接理解为会随着请求而变化的值,事实上在 协程 编程中,这些状态值也是应该存放于协程上下文
中的,即Hyperf\Utils\Context
。短生命周期对象
通过
new
关键词创建的对象毫无疑问的短生命周期的,那么如果希望创建一个短生命周期的对象但又希望使用构造函数依赖自动注入功能
呢?这时我们可以通过make(string $name, array $parameters = [])
函数来创建$name
对应的的实例,代码示例如下:$userService = make(UserService::class, ['enableCache' => true]);Copy to clipboardErrorCopied
注意仅
$name
对应的对象为短生命周期对象,该对象的所有依赖都是通过get()
方法获取的,即为长生命周期的对象获取容器对象
有些时候我们可能希望去实现一些更动态的需求时,会希望可以直接获取到
容器(Container)
对象,在绝大部分情况下,框架的入口类(比如命令类、控制器、RPC 服务提供者等)都是由容器(Container)
创建并维护的,也就意味着您所写的绝大部分业务代码都是在容器(Container)
的管理作用之下的,也就意味着在绝大部分情况下您都可以通过在构造函数(Constructor)
声明或通过@Inject
注解注入Psr\Container\ContainerInterface
接口类都能够获得Hyperf\Di\Container
容器对象,我们通过代码来演示一下:<?php namespace App\Controller; use Hyperf\HttpServer\Annotation\AutoController; use Psr\Container\ContainerInterface; class IndexController { /** * @var ContainerInterface */ private $container; // 通过在构造函数的参数上声明参数类型完成自动注入 public function __construct(ContainerInterface $container) { $this->container = $container; } }Copy to clipboardErrorCopied
在某些更极端动态的情况下,或者非
容器(Container)
的管理作用之下时,想要获取到容器(Container)
对象还可以通过\Hyperf\Utils\ApplicationContext::getContaienr()
方法来获得容器(Container)
对象。$container = \Hyperf\Utils\ApplicationContext::getContainer();
执行顺序为:全局中间件 -> 类级别中间件 -> 方法级别中间件
。
-
全局更改请求和响应对象
首先,在协程上下文内是有存储最原始的 PSR-7
请求对象
和响应对象
的,且根据 PSR-7 对相关对象所要求的不可变性(immutable)
,也就意味着我们在调用$response = $response->with***()
所调用得到的$response
,并非为改写原对象,而是一个Clone
出来的新对象,也就意味着我们储存在协程上下文内的请求对象
和响应对象
是不会改变的,那么当我们在中间件内的某些逻辑改变了请求对象
或响应对象
,而且我们希望对后续的 非传递性的 代码再获取改变后的请求对象
或响应对象
,那么我们便可以在改变对象后,将新的对象设置到上下文中,如代码所示:use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; // $request 和 $response 为修改后的对象 $request = \Hyperf\Utils\Context::set(ServerRequestInterface::class, $request); $response = \Hyperf\Utils\Context::set(ResponseInterface::class, $response);