- 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()
获取容器对象
有些时候我们可能希望去实现一些更动态的需求时,会希望可以直接获取到
对象,在绝大部分情况下,框架的入口类(比如命令类、控制器、RPC 服务提供者等)都是由容器(Container)
创建并维护的,也就意味着您所写的绝大部分业务代码都是在容器(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)
- 中间件的执行顺序
执行顺序为:
全局中间件 -> 类级别中间件 -> 方法级别中间件
。
-
全局更改请求和响应对象
首先,在协程上下文内是有存储最原始的 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);