Hyperf 2.0 发布!想象的开端!

前言

Hyperf 从 2019 年 6 月 20 日发布 1.0 版本至今,获得了非常多的关注和用户,短短的一年期间,Hyperf 飞速发展和持续迭代,同时也拥有了非常惊人的数据。

  • Github 2700 stars / Gitee 328 stars
  • 113 名 contributors
  • 1100+ Pull Requests
  • 共发布 47 个版本
  • 92 个代码仓库
  • 1438 个单元测试用例,4412 个断言条件

这些数据是整个开源社区共同努力的结果,感谢所有支持 Hyperf 的大神的厚爱,期待未来更多的支持与合作。

Hyperf 2.0

在持续迭代的过程中,我们也产生了一些新的思路,我们对这些思路进行了验证、迭代、再验证、再迭代,并最终将这些思路的实现沉淀到了 Hyperf 中来,并于今日,以 2.0 版本正式发布了 🎉🎉🎉

感谢 Hyperf 团队成员日以继夜的努力,使这些设想成为了可能。

主要功能迭代

AOP 和注解功能底层重构

在 1.1 版本下,尽管提供了非常强大的 AOP 和注解功能,但也仍有一些限制和不足如下:

  • AOP 只能切入由 hyperf/di 组件管理的对象,无法切入其它方式创建的对象,如 new
  • 通过 DI 获取的类实际上是由 AOP 生成的一个原始类的子类,在子类上完成了对方法的修改,以完成 AOP 的功能实现,而子类的类名与原始类是不一致的,也就导致了 get_class(), __CLASS__ 之类的方法或常量获取的数据可能会不对;
  • 同上,异常堆栈信息会充满了代理类的链路,不容易看清楚调用链路;
  • 同上,由于是通过继承实现的代理类,故一个 final 类是无法被切入的;
  • 同上,对一个父类进行 AOP 切入后,这个类的子类并不会被切入;
  • 通过 new 实例化的一个对象 @Inject@Value 注解无法生效;
  • 您无法在一个类的构造函数内使用通过 @Inject@Value 注解获取的值;
  • 在 trait 内通过 @Inject@Value 注解标注的属性无法正常运作;
  • 在 PHP 8 下无法通过类成员属性的强类型声明替代 @var 声明来指定 @Inject 时的类声明;
  • 使用注解时必须声明对应注解的命名空间;
  • 定义 Aspect 类时无法在注解上一并定义要切入的目标;

以上列举了一些 1.1 下 AOP 的限制和不足,而在 2.0 版本下,我们对底层的逻辑进行了重构,上面这些问题全部都被解决掉了,其中最具想象空间的是通过新的 AOP 功能,你可以对几乎所有的类和注解进行动态的切入了,无论是通过 new 实例化出来的对象还是通过 DI 创建出来的对象,无论是切入了这个类的父类还是更深的继承层次,无论是 final 类还是一个普通类。

简而言之,在新的机制下,Hyperf 会在启动时扫描所有的扫描域,并扫描代码得到所有类的 AST 抽象语法树,并从中解析所有与 AOP 相关的元数据,根据这些元数据来对要被代理的类进行 AST 节点信息的修改,并注入 AOP 相关的逻辑,最终通过 PHP 的 Autoload 机制,在实例化一个类并进行自动加载时,ClassLoader 返回经过修改后的类文件。

那么用正向的角度来描述这个功能的变更如下:

  • AOP 可以作用于 new 关键词创建的对象;
  • AOP 可以作用于 Final 类;
  • 您可以在构造函数中使用 @Inject@Value 注解标记的属性值;
  • 代理类的类名和继承关系与原类一致;
  • 对父类进行 AOP 切入,子类同样生效;
  • AOP 代理类缓存和注解缓存可以自动识别是否需要重新生成;
  • 通过 new 关键词创建的对象,@Inject@Value 注解标记的属性值可以生效;
  • 可在 trait 中使用 @Inject@Value 注解,并作用于 use 的类;
  • PHP 8 下使用 @Inject 注解时可通过强类型声明替代 @var 注解声明;
  • 提供了注解全局引入机制,以达到在使用注解时允许不引入对应的命名空间;
  • 在定义 Aspect 时可直接在 @Aspect 注解上定义要切入的目标类和注解;
  • Aspect 增加了 priority 优先级属性,可定义多个 Aspect 类的优先级;
  • 使用依赖懒加载功能时无需再注册 Hyperf\Di\Listener\LazyLoaderBootApplicationListener 监听器;
  • 新增 annotations.scan.class_map 配置,通过该配置可以直接将任意类替换为你指定的类;

支持 Coroutine Server 协程服务

在 Swoole 4.4 版本时新增了 Coroutine Server,通过该功能可以通过协程的形式来运行 Server,也就意味着可以在一个进程下同时运行多个不同协议的 Server 来提供服务,这样的做法更加的协程,且单进程的模型对 Docker 和 Kubernetes 更加友好,通过调整 Pod 的数量即可对应到真实的进程数;
在 Hyperf 2.0 版本,我们也对 Coroutine Server 进行了支持,您可通过在 config/autoload/server.php 配置文件中添加一个 type => Hyperf\Server\CoroutineServer::class 配置即可切换到 Coroutine Server 的运行模式去。同时一些原本要使用自定义进程来实现功能的场景,如配置中心的配置拉取、服务监控的数据提供、消息队列消费者的消费等,我们的提供了对应的协程模式的运行模式,最终只需要启动一个进程即可完成所有之前需要多个进程才能完成的事情。

增加 ResponseEmitter 机制

在 1.1 版本下,我们只能在 HTTP Server 中返回由 hyperf/http-message 组件或 hyperf/http-server 组件提供的 Response 对象,但其它同样遵循了 PSR-7 标准的 Response 却无法正常响应,比如 Guzzle 客户端请求后获得的 Response 对象,在 1.1 下需要转换为 Hyperf 的 Response 对象才能正确响应客户端请求。而在 2.0 版本下,通过 ResponseEmitter 机制,您可以直接返回任意符合 PSR-7 标准的 Response 对象,以获得更强的兼容性。

增加 Reactive-X 组件

hyperf/reactive-x 组件提供了 Swoole/Hyperf 环境下的 ReactiveX 集成。关于 ReactiveX,微软给的定义是,Rx 是一个函数库,让开发者可以利用可观察序列和 LINQ 风格查询操作符来编写异步和基于事件的程序,使用 Rx,开发者可以用 Observables 表示异步数据流,用 LINQ 操作符查询异步数据流, 用 Schedulers 参数化异步数据流的并发处理,Rx 可以这样定义:Rx = Observables + LINQ + Schedulers。而 Reactivex.io 给的定义是,Rx 是一个使用可观察数据流进行异步编程的编程接口,ReactiveX 结合了观察者模式、迭代器模式和函数式编程的精华。

通过该组件,您可以在 Hyperf 中实现响应式编程的范式,为您的应用提供更多的可能性。

统一 HTTP 异常

在 1.1 版本下,HTTP Server 在处理如 路由未找到(404)请求方法不允许(405) 等 HTTP 异常时,是在 Dispatcher 中提供对应的方法,并直接响应 Response 结果,如果需要自定义对应的响应结果,则需要通过 DI 来重写 Dispatcher 类的对应方法。而在 2.0 版本下,我们对异常的处理方式进行了统一,统一抛出 Hyperf\HttpMessage\Exception\HttpException 异常类的子类,并统一由默认提供的 Hyperf\HttpServer\Exception\Handler\HttpExceptionHandler 来处理响应的结果,这样一来用户便可以非常便捷的通过 ExceptionHandler 来对异常响应进行统一的处理了。

升级到 2.0 版本

从现在的 1.1 版本升级到 2.0 版本,也是一件非常轻松的事情,我们提供了一份详尽的 2.0 升级指南 来指引您完成对应的升级动作,具体可查阅该升级指南;

更多

以上只是笔者本人最为期待的功能迭代,只是冰山一角,2.0 版本还包含了大量的细节更新以及新功能,具体可以查阅 版本更新记录 获得更多的细节信息。

总的来说,2.0 是一个充满了想象空间的版本,它提供了远超原来的可能性,我们可以在 Hyperf 上、在 Swoole 上、在 PHP 上,去想、去做更多原来不曾深思过的事情。

本作品采用《CC 协议》,转载必须注明作者和本文链接
本帖由系统于 5个月前 自动加精
讨论数量: 9

这样的好文居然没人来点赞评论?!!!!!

3个月前 评论

以前我也喜欢这种框架,现在挺钟于laravel

2个月前 评论
huangzhhui (楼主) 2个月前

挺好的,我们公司就在用

2个月前 评论

支持一下 虽然没使用

2个月前 评论

支持,我现在也在用 :+1:

2个月前 评论

大佬,麻烦问一下,hyperf 在验证器获取 http 请求参数 c.created 类似这种的都把 . 替换成了 c_created,使用 swoole 的 Swoole\Http\Request 提示警告 Warning: Swoole\Http\Request::getContent(): http request is unavailable (maybe it has been ended) ,请问应该怎么获取不经过处理的参数呢

2个月前 评论

可以把路由的文件放在根目录下吗?放在config下总是忘记在哪。

1个月前 评论
huangzhhui (楼主) 1个月前

有用过,整挺好~ 支持

1个月前 评论

缓存 使用注解,只能缓存数据库一条记录吗,生成的KEY必须要是拼接数据库的id吗

1个月前 评论
李铭昕 2周前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!