天天看點

hyperf使用需要注意的地方

  1. jwt DateTimeImmutable 報錯:

jwt DateTimeImmutable 問題 降低版本到3.3.3解決問題: composer require lcobucci/jwt:3.3.3

  1. hyperf使用注解的坑,hyperf使用注解會讓注解的執行個體變為單例,

問題1:model産生問題 ***

如果我們注解一個model給變量,當有兩個地方會查詢資料,第一個查詢會是A+B連接配接查詢,第二個是A+B+C連接配接查詢,如果第二個查詢有一個參數時C的,執行二後在執行第一個會導緻報錯,報C中的參數不存在,機關這個執行個體是單例的,第二個查詢的參數不會被清除,

問題二:執行個體化時如果帶參數 ***

如果執行個體化帶參數,第一個執行個體化帶了一個參數,第二個操作時不會重新執行個體化,這樣會導緻第二次使用還是第一次的參數,導緻出錯

問題三:公共屬性

在控制器中一個屬性被改變,後面再有請求來擷取屬性時擷取到是最新的,不是初始化的,

  1. Inject或Value注解不生效

    使用了構造函數中注入

    Inject

    Value

    的功能,以下兩種場景,可能會導緻注入失效,請注意使用。
    1. 原類沒有使用

      Inject

      Value

      ,但父類使用了

      Inject

      Value

      ,且原類寫了構造函數,同時又沒有調用父類構造函數的情況。

    這樣就會導緻原類不會生成代理類,而執行個體化的時候又調用了自身的構造函數,故沒辦法執行到父類的構造函數。

    是以父類代理類中的方法

    __handlePropertyHandler

    就不會執行,那麼

    Inject

    Value

    注解就不會生效。
    class ParentClass {
        /**
         * @Inject
         * @var Service
         */
        protected $value;
    }
    
    class Origin extends ParentClass
    {
        public function __construct() {}
    }
               
    1. 原類沒有使用

      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;
}
           
  1. 一般建議使用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 = [])
               
  2. 注意事項

    注意事項

    容器僅管理長生命周期的對象

    換種方式了解就是容器内管理的對象都是單例,這樣的設計對于長生命周期的應用來說會更加的高效,減少了大量無意義的對象建立和銷毀,這樣的設計也就意味着所有需要交由 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)

    對象。
  3. 中間件的執行順序

執行順序為:

全局中間件 -> 類級别中間件 -> 方法級别中間件

  1. 全局更改請求和響應對象

    首先,在協程上下文内是有存儲最原始的 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);