- 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);