hyperf使用需要注意的地方

6 篇文章 0 订阅
2 篇文章 0 订阅
  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注解不生效

    使用了构造函数中注入 InjectValue 的功能,以下两种场景,可能会导致注入失效,请注意使用。

    1. 原类没有使用 InjectValue,但父类使用了 InjectValue,且原类写了构造函数,同时又没有调用父类构造函数的情况。

    这样就会导致原类不会生成代理类,而实例化的时候又调用了自身的构造函数,故没办法执行到父类的构造函数。
    所以父类代理类中的方法 __handlePropertyHandler 就不会执行,那么 InjectValue 注解就不会生效。

    class ParentClass {
        /**
         * @Inject
         * @var Service
         */
        protected $value;
    }
    
    class Origin extends ParentClass
    {
        public function __construct() {}
    }
    
    1. 原类没有使用 InjectValue,但 Trait 中使用了 InjectValue

    这样就会导致原类不会生成代理类,故没办法执行构造函数里的 __handlePropertyHandler,所以 TraitInjectValue 注解就不会生效。

    trait OriginTrait {
        /**
         * @Inject
         * @var Service
         */
        protected $value;
    }
    
    class Origin
    {
        use OriginTrait;
    }
    

基于上述两种情况,可见 原类 是否生成代理类至关重要,所以,如果使用了带有 InjectValueTrait父类 时,给原类添加一个 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) 对象。

    $container = \Hyperf\Utils\ApplicationContext::getContainer();
    
  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);
    
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Hyperf框架可以使用PHP内置的Timer来实现定时任务功能,具体步骤如下: 1. 在composer.json文件中添加swoole扩展: ```json "require": { "php": ">=7.2", "hyperf/hyperf": "~1.1", "swoole/ide-helper": "^4.4|^5.0", "swoole": "^4.4|^5.0" }, ``` 2. 创建一个任务类,继承Hyperf\Task\Task类,实现handle()方法,用于处理具体的定时任务逻辑: ```php <?php namespace App\Task; use Hyperf\Task\Annotation\Task; class MyTask { /** * @Task() */ public function handle() { // 处理定时任务逻辑 } } ``` 3. 在config/autoload/tasks.php中配置定时任务: ```php return [ // 定时任务 'crontab' => [ // 每分钟执行一次 MyTask 类的 handle() 方法 '* * * * *' => [ App\Task\MyTask::class, // 可选参数,用于传递参数给handle()方法 [ 'param1' => 'value1', 'param2' => 'value2', ] ], ], ]; ``` 4. 在启动脚本中调用Hyperf\Utils\Coroutine::enableScheduler()方法开启协程调度器: ```php <?php use Hyperf\Utils\Coroutine; require_once __DIR__ . '/../vendor/autoload.php'; Coroutine::set([ 'max_coroutine' => 100000, ]); // 开启协程调度器 Coroutine::enableScheduler(); // 创建容器 $container = \Hyperf\Di\Container::create(); // 创建应用 $application = new \Hyperf\Contract\ApplicationInterface($container); // 启动应用 $application->run(); ``` 5. 在控制台中执行hyperf命令,启动定时任务: ``` php bin/hyperf.php crontab:start ``` 6. 定时任务启动后,将会按照配置的时间间隔执行MyTask类的handle()方法。可以通过hyperf命令查看定时任务列表: ``` php bin/hyperf.php crontab:list ``` 7. 如果需要停止定时任务,可以执行以下命令: ``` php bin/hyperf.php crontab:stop ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值