本文是根据Hyperf官方文档 的学习日志, 看官请直接访问 Hyperf
什么是Hyperf ?
Hyperspeed + Flexibility = Hyperf
Hyperf 是基于 Swoole 4.4+
实现的高性能、高灵活性的 PHP 协程框架,内置协程服务器及大量常用的组件,性能较传统基于 PHP-FPM 的框架有质的提升,提供超高性能的同时,也保持着极其灵活的可扩展性,标准组件均基于 PSR 标准 实现,基于强大的依赖注入设计,保证了绝大部分组件或类都是 可替换 与 可复用 的。
安装Hyperf 服务器要求 Hyperf
对系统环境有一些要求,仅可运行于 Linux
和 Mac
环境下 ,但由于 Docker
虚拟化技术的发展,在 Windows
下也可以通过 Docker for Windows
来作为运行环境
hyperf-cloud\hyperf-docker 项目内已经为您准备好了各种版本的 Dockerfile ,或直接基于已经构建好的 hyperf\hyperf 镜像来运行。
确保你的运行环境达到了以下的要求:
PHP >= 7.2
Swoole PHP
扩展 >= 4.4
,并关闭了 Short Name
OpenSSL PHP
扩展
JSON PHP
扩展
PDO PHP
扩展 (如需要使用到 MySQL 客户端)
Redis PHP
扩展 (如需要使用到 Redis 客户端)
Protobuf PHP
扩展 (如需要使用到 gRPC 服务端或客户端)
查看Swoole扩展版本 1 2 3 4 5 6 7 8 [root@caoxl ~]# php --ri swoole swoole Swoole => enabled Author => Swoole Team <team@swoole.com> Version => 4.4.7 Built => Oct 11 2019 10:26:37
升级Swoole扩展
升级swoole版本的常见问题
查看PHP版本 1 2 3 4 5 [root@caoxl ~]# php -v PHP 7.2.7 (cli) (built: Nov 15 2018 11:33:02) ( NTS ) Copyright (c) 1997-2018 The PHP Group Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies with Zend OPcache v7.2.7, Copyright (c) 1999-2018, by Zend Technologies
升级PHP版本
Linux 下安装开发环境(多版本PHP)
安装Hyperf Composer 安装 1 composer create-project hyperf/hyperf-skeleton
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 [root@caoxl www]# composer create-project hyperf/hyperf-skeleton Do not run Composer as root/super user! See https://getcomposer.org/root for details Installing hyperf/hyperf-skeleton (v1.1.0) - Installing hyperf/hyperf-skeleton (v1.1.0): Downloading (100%) Created project in /var/www/hyperf-skeleton > @php -r "file_exists('.env') || copy('.env.example', '.env');" > Installer\Script::install Setting up optional packages Setup data and cache dir Removing installer development dependencies ... Writing lock file Generating autoload files ocramius/package-versions: Generating version class... ocramius/package-versions: ...done generating version class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 [root@caoxl hyperf-skeleton]# ll -s total 344K 4.0K drwxrwxr-x 6 root root 4.0K Oct 8 01:26 app 4.0K drwxrwxr-x 2 root root 4.0K Oct 8 01:26 bin 4.0K -rw-rw-r-- 1 root root 2.6K Oct 11 10:41 composer.json 296K -rw-rw-r-- 1 root root 295K Oct 11 10:41 composer.lock 4.0K drwxrwxr-x 3 root root 4.0K Oct 8 01:26 config 4.0K -rw-rw-r-- 1 root root 580 Oct 8 01:26 deploy.test.yml 4.0K -rw-rw-r-- 1 root root 1.6K Oct 8 01:26 Dockerfile 4.0K -rw-rw-r-- 1 root root 339 Oct 8 01:26 phpstan.neon 4.0K -rw-rw-r-- 1 root root 695 Oct 8 01:26 phpunit.xml 4.0K -rw-rw-r-- 1 root root 2.3K Oct 8 01:26 README.md 4.0K drwxrwxr-x 2 root root 4.0K Oct 11 10:40 runtime 4.0K drwxrwxr-x 3 root root 4.0K Oct 8 01:26 test 4.0K drwxrwxr-x 44 root root 4.0K Oct 11 10:41 vendor
Dockter 下开发 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 # 下载并运行 hyperf/hyperf 镜像,并将镜像内的项目目录绑定到宿主机的 /tmp/skeleton 目录 docker run -v /tmp/skeleton:/hyperf-skeleton -p 9501:9501 -it --entrypoint /bin/sh hyperf/hyperf:7.2-alpine-cli # 镜像容器运行后,在容器内安装 Composer wget https://github.com/composer/composer/releases/download/1.8.6/composer.phar chmod u+x composer.phar mv composer.phar /usr/local/bin/composer # 将 Composer 镜像设置为阿里云镜像,加速国内下载速度 composer config -g repo.packagist composer https://mirrors.aliyun.com/composer # 通过 Composer 安装 hyperf/hyperf-skeleton 项目 composer create-project hyperf/hyperf-skeleton # 进入安装好的 Hyperf 项目目录 cd hyperf-skeleton # 启动 Hyperf php bin/hyperf.php start
接下来,就可以在 /tmp/skeleton
中看到您安装好的代码了。由于 Hyperf
是持久化的 CLI
框架,当您修改完您的代码后,通过 CTRL + C
终止当前启动的进程实例,并重新执行 php bin/hyperf.php start
启动命令即可。
存在兼容性问题的扩展 由于 Hyperf
基于 Swoole
协程实现,而 Swoole 4
带来的协程功能是 PHP 前所未有的,所以与不少扩展都仍存在兼容性的问题。 以下扩展(包括但不限于)都会造成一定的兼容性问题,不能与之共用或共存:
xhprof
xdebug
blackfire
trace
uopz
快速开始 为了让您更快的了解 Hyperf
的使用,本章节将以 创建一个 HTTP Server
为例,通过对路由、控制器的定义实现一个简单的 Web
服务,但 Hyperf
不止于此,完善的服务治理、gRPC
服务、注解、AOP
等功能将由具体的章节阐述。
定义访问路由 Hyperf
使用 nikic/fast-route 作为默认的路由组件并提供服务,您可以很方便的在 config/routes.php
中定义您的路由。
通过配置文件定义路由 路由的文件位于 hyperf-skeleton
项目的 config/routes.php
,下面是一些常用的用法示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <?php declare (strict_types=1 );use Hyperf \HttpServer \Router \Router ;Router ::addRoute (['GET' , 'POST' , 'HEAD' ], '/' , 'App\Controller\IndexController@index' );Router ::get ('/get' , 'App\Controller\IndexController::get' );Router ::get ('/get' , 'App\Controller\IndexController@get' );Router ::get ('/get' , [\App\Controller\IndexController ::class , 'get' ]);Router ::post ('/post' , 'App\Controller\IndexController::post' );Router ::post ('/post' , 'App\Controller\IndexController@post' );Router ::post ('/post' , [\App\Controller\IndexController ::class , 'post' ]);Router ::addRoute (['GET' , 'POST' , 'HEAd' ], 'multi' , 'App\Controller\IndexController::multi' );Router ::addRoute (['GET' , 'POST' , 'HEAd' ], 'multi' , 'App\Controller\IndexController@multi' );Router ::addRoute (['GET' , 'POST' , 'HEAd' ], 'multi' , [\App\Controller\IndexController ::class , 'multi' ]);
通过注解来定义路由 Hyperf
提供了极其强大和方便灵活的 注解 功能,在路由的定义上也毫无疑问地提供了注解定义的方式,Hyperf
提供了 @Controller
和 @AutoController
两种注解来定义一个 Controller
.
通过 @AutoController
注解定义路由 @AutoController
为绝大多数简单的访问场景提供路由绑定支持,使用 @AutoController
时则 Hyperf
会自动解析所在类的所有 public
方法并提供 GET
和 POST
两种请求方式。
使用 @AutoController
注解时需 use Hyperf\HttpServer\Annotation\AutoController;
命名空间;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?php declare (strict_types=1 );namespace App \Controller ;use Hyperf \HttpServer \Contract \RequestInterface ;use Hyperf \HttpServer \Annotation \AutoController ;class IndexController { public function index (RequestInterface $request ) { $id = $request ->input ('id' , 1 ); return (string )$id ; } }
通过 @Controller
注解定义路由 @Controller
为满足更细致的路由定义需求而存在,使用 @Controller
注解用于表明当前类为一个 Controller
类,同时需配合 @RequestMapping
注解来对请求方法和请求路径进行更详细的定义。
使用 @Controller
注解时需 use Hyperf\HttpServer\Annotation\Controller;
命名空间;
使用 @RequestMapping
注解时需 use Hyperf\HttpServer\Annotation\RequestMapping;
命名空间;
使用 @GetMapping
注解时需 use Hyperf\HttpServer\Annotation\GetMapping;
命名空间;
使用 @PostMapping
注解时需 use Hyperf\HttpServer\Annotation\PostMapping;
命名空间;
使用 @PutMapping
注解时需 use Hyperf\HttpServer\Annotation\PutMapping;
命名空间;
使用 @PatchMapping
注解时需 use Hyperf\HttpServer\Annotation\PatchMapping;
命名空间;
使用 @DeleteMapping
注解时需 use Hyperf\HttpServer\Annotation\DeleteMapping;
命名空间;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <?php declare (strict_types=1 );namespace App \Controller ;use Hyperf \HttpServer \Contract \RequestInterface ;use Hyperf \HttpServer \Annotation \Controller ;use Hyperf \HttpServer \Annotation \RequestMapping ;class IndexController { public function index (RequestInterface $request ) { $id = $request ->input ('id' , 1 ); return (string )$id ; } }
处理HTTP请求 Hyperf
是完全开放的,本质上没有规定您必须基于某种模式下去实现请求的处理,您可以采用传统的 MVC模式
,亦可以采用 RequestHandler模式
来进行开发。
在 app 文件夹内创建一个 Controller 文件夹并创建 IndexController.php 如下,index 方法内从请求中获取了 id 参数,并转换为 字符串 类型返回到客户端。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?php declare (strict_types=1 );namespace App \Controller ;use Hyperf \HttpServer \Contract \RequestInterface ;use Hyperf \HttpServer \Annotation \AutoController ;class IndexController { public function index (RequestInterface $request ) { $id = $request ->input ('id' , 1 ); return (string )$id ; } }
依赖自动注入 依赖自动注入是 Hyperf
提供的一个非常强大的功能,也是保持框架灵活性的根基。Hyperf
提供了两种注入方式,一种是大家常见的通过构造函数注入,另一种是通过 @Inject
注解注入
通过构造函数注入 只需在构造函数的参数内声明参数的类型,Hyperf
会自动注入对应的对象或值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <?php declare (strict_types=1 );namespace App \Controller ;use Hyperf \HttpServer \Contract \RequestInterface ;use Hyperf \HttpServer \Annotation \AutoController ;use App \Service \UserService ;class IndexController { private $userService ; public function __construct (UserService $userService ) { $this ->userService = $userService ; } public function info (RequestInterface $request ) { $id = $request ->input ('id' , 1 ); return $this ->userService->getInfoById ((int )$id ); } }
通过 @Inject
注解注入 只需对对应的类属性通过 @var
声明参数的类型,并使用 @Inject
注解标记属性 ,Hyperf
会自动注入对应的对象或值。
使用 @Inject
注解时需 use Hyperf\Di\Annotation\Inject;
命名空间;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <?php declare (strict_types=1 );namespace App \Controller ;use Hyperf \HttpServer \Contract \RequestInterface ;use Hyperf \HttpServer \Annotation \AutoController ;use Hyperf \Di \Annotation \Inject ;use App \Service \UserService ;class IndexController { private $userService ; public function info (RequestInterface $request ) { $id = $request ->input ('id' , 1 ); return $this ->userService->getInfoById ((int )$id ); } }
启动 Hyperf 服务 由于 Hyperf
内置了协程服务器,也就意味着 Hyperf
将以 CLI
的形式去运行,所以在定义好路由及实际的逻辑代码之后,我们需要在项目根目录并通过命令行运行 php bin/hyperf.php start
来启动服务。
1 2 3 4 5 [root@caoxl hyperf-skeleton]# php bin/hyperf.php start Detected an available cache, skip the app scan process. Detected an available cache, skip the vendor scan process. [DEBUG] Event Hyperf\Framework\Event\BootApplication handled by Hyperf\Di\Listener\BootApplicationListener listener. ...
当 Console
界面显示服务启动后便可通过 cURL 或 浏览器对服务正常发起访问了,默认服务会提供一个首页 http://127.0.0.1:9501/
,对于本章示例引导的情况下,也就是上面的例子所对应的访问地址为 http://127.0.0.1:9501/index/info?id=1
。
访问 : http://caoxl.com:9501/
1 2 3 4 { method: "GET", message: "Hello Hyperf." }
重新加载代码 由于 Hyperf
是持久化的 CLI
应用,也就意味着一旦进程启动,已解析的 PHP 代码会持久化在进程中,也就意味着启动服务后您再修改的 PHP
代码不会改变已启动的服务,如希望服务重新加载您修改后的代码,需要通过在启动的 Console
中键入 CTRL + C
终止服务,再重新执行启动命令完成重启和重新加载。
核心架构 生命周期 框架生命周期 Hyperf
是运行于 Swoole 之上的,想要理解透彻 Hyperf
的生命周期,那么理解 Swoole 的生命周期也至关重要。Hyperf
的命令管理默认由 symfony/console
提供支持(如果您希望更换该组件您也可以通过改变 skeleton 的入口文件更换成您希望使用的组件 ),在执行 php bin/hyperf.php start
后,将由 Hyperf\Server\Command\StartServer
命令类接管,并根据配置文件 config/autoload/server.php
内定义的 Server
逐个启动。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 [DEBUG] Event Hyperf\Framework\Event\BootApplication handled by Hyperf\Di\Listener\BootApplicationListener listener. [DEBUG] Event Hyperf\Framework\Event\BootApplication handled by Hyperf\Config\Listener\RegisterPropertyHandlerListener listener. [DEBUG] Event Hyperf\Framework\Event\BootApplication handled by Hyperf\Paginator\Listener\PageResolverListener listener. [DEBUG] Event Hyperf\Framework\Event\BeforeMainServerStart handled by Hyperf\Amqp\Listener\BeforeMainServerStartListener listener. [DEBUG] Event Hyperf\Framework\Event\BeforeMainServerStart handled by Hyperf\Process\Listener\BootProcessListener listener. [DEBUG] Event Hyperf\Framework\Event\OnStart handled by Hyperf\Server\Listener\InitProcessTitleListener listener. [DEBUG] Event Hyperf\Framework\Event\OnManagerStart handled by Hyperf\Server\Listener\InitProcessTitleListener listener. [DEBUG] Event Hyperf\Framework\Event\MainWorkerStart handled by Hyperf\Amqp\Listener\MainWorkerStartListener listener. [INFO] Worker#0 started. [DEBUG] Event Hyperf\Framework\Event\AfterWorkerStart handled by Hyperf\Server\Listener\InitProcessTitleListener listener. [INFO] HTTP Server listening at 0.0.0.0:9501 [DEBUG] Event Hyperf\Framework\Event\AfterWorkerStart handled by Hyperf\Server\Listener\AfterWorkerStartListener listener. [INFO] Worker#1 started. [DEBUG] Event Hyperf\Framework\Event\AfterWorkerStart handled by Hyperf\Server\Listener\InitProcessTitleListener listener. [DEBUG] Event Hyperf\Framework\Event\AfterWorkerStart handled by Hyperf\Server\Listener\AfterWorkerStartListener listener.
关于依赖注入容器的初始化工作,并没有由组件来实现,因为一旦交由组件来实现,这个耦合就会非常的明显,所以在默认的情况下,是由入口文件来加载 config/container.php
来实现的。
请求与协程生命周期 Swoole
在处理每个连接时,会默认创建一个协程去处理,主要体现在 onRequest
、onReceive
、onConnect
事件,所以可以理解为每个请求都是一个协程,由于创建协程也是个常规操作,所以一个请求协程里面可能会包含很多个协程,同一个进程内协程之间是内存共享的,但调度顺序是非顺序的,且协程间本质上是相互独立的没有父子关系,所以对每个协程的状态处理都需要通过 协程上下文 来管理。
协程上下文 由于同一个进程内协程间是内存共享的,但协程的执行/切换是非顺序的,也就意味着我们很难掌控当前的协程是哪一个(事实上可以,但通常没人这么干),所以我们需要在发生协程切换时能够同时切换对应的上下文。
在 Hyperf
里实现协程的上下文管理将非常简单,基于 Hyperf\Utils\Context
类的 set(string $id, $value)
、get(string $id, $default = null)
、has(string $id)
、override(string $id, \Closure $closure)
静态方法即可完成上下文数据的管理,通过这些方法设置和获取的值,都仅限于当前的协程,在协程结束时,对应的上下文也会自动跟随释放掉,无需手动管理,无需担忧内存泄漏的风险。
Hyperf\Utils\Context::set()
通过调用 set(string $id, $value)
方法储存一个值到当前协程的上下文中,如下:
1 2 3 4 5 6 <?php use Hyperf \Utils \Context ;$foo = Context ::set ('foo' , 'bar' );
Hyperf\Utils\Context::get()
通过调用 get(string $id, $default = null)
方法可从当前协程的上下文中取出一个以 $id
为 key
储存的值,如不存在则返回 $default
,如下:
1 2 3 4 5 <?php use Hyperf \Utils \Context ;$foo = Context ::get ('foo' , 'bar' );
Hyperf\Utils\Context::has()
通过调用 has(string $id)
方法可判断当前协程的上下文中是否存在以 $id
为 key
储存的值,如存在则返回 true
,不存在则返回 false
,如下:
1 2 3 4 5 <?php use Hyperf \Utils \Context ;$foo = Context ::has ('foo' );
Hyperf\Utils\Context::override()
Override 方法仅可在 1.0.12 版本或更高版本使用
当我们需要做一些复杂的上下文处理,比如先判断一个 key
是否存在,如果存在则取出 value
来再对 value
进行某些修改,然后再将 value
设置回上下文容器中,此时会有比较繁杂的判断条件,可直接通过调用 override
方法来实现这个逻辑,如下:
1 2 3 4 5 6 7 8 <?php use Psr \Http \Message \ServerRequestInterface ;use Hyperf \Utils \Context ;$request = Context ::override (ServerRequestInterface ::class , function (ServerRequestInterface $request ) { return $request ->withAddedHeader ('foo' , 'bar' ); });
协程 概念 Hyperf
是运行于 Swoole 4
的协程之上的,这也是 Hyperf 能提供高性能的其中一个很大的因素。
Hyperf 协程 Swoole 协程
配置 安装 1 composer require hyperf/config
配置文件结构 以下结构仅为 Hyperf-Skeleton
所提供的默认配置的情况下的结构,实际情况由于依赖或使用的组件的差异,文件会有差异。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 config ├── autoload // 此文件夹内的配置文件会被配置组件自己加载,并以文件夹内的文件名作为第一个键值 │ ├── amqp.php // 用于管理 AMQP 组件 │ ├── annotations.php // 用于管理注解 │ ├── apollo.php // 用于管理基于 Apollo 实现的配置中心 │ ├── aspects.php // 用于管理 AOP 切面 │ ├── async_queue.php // 用于管理基于 Redis 实现的简易队列服务 │ ├── cache.php // 用于管理缓存组件 │ ├── commands.php // 用于管理自定义命令 │ ├── consul.php // 用于管理 Consul 客户端 │ ├── databases.php // 用于管理数据库客户端 │ ├── devtool.php // 用于管理开发者工具 │ ├── exceptions.php // 用于管理异常处理器 │ ├── listeners.php // 用于管理事件监听者 │ ├── logger.php // 用于管理日志 │ ├── middlewares.php // 用于管理中间件 │ ├── opentracing.php // 用于管理调用链追踪 │ ├── processes.php // 用于管理自定义进程 │ ├── redis.php // 用于管理 Redis 客户端 │ └── server.php // 用于管理 Server 服务 ├── config.php // 用于管理用户或框架的配置,如配置相对独立亦可放于 autoload 文件夹内 ├── container.php // 负责容器的初始化,作为一个配置文件运行并最终返回一个 Psr\Container\ContainerInterface 对象 ├── dependencies.php // 用于管理 DI 的依赖关系和类对应关系 └── routes.php // 用于管理路由
设置配置 只需在 config/config.php
与 config/autoload/server.php
与 autoload
文件夹内的配置,都能在服务启动时被扫描并注入到 Hyperf\Contract\ConfigInterface
对应的对象中,这个流程是由 Hyperf\Config\ConfigFactory
在 Config
对象实例化时完成的。
获取配置 Config 组件提供了三种方式获取配置,
通过 Hyperf\Config\Config
对象获取
1 2 3 4 5 /** * @var \Hyperf\Contract\ConfigInterface */ // 通过 get(string $key, $default): mixed 方法获取 $key 所对应的配置,$key 值可以通过 . 连接符定位到下级数组,$default 则是当对应的值不存在时返回的默认值 $config->get($key,$default);
1 2 3 4 5 6 7 8 9 10 11 12 class IndexController { /** * @Value("config.key") */ private $configValue; public function index() { return $this->configValue; } }
通过 config(string $key, $default)
函数获取。
在任意地方可以通过 config(string $key, $default)
函数获取对应的配置,但这样的使用方式也就意味着您对 hyperf/config
和 hyperf/utils
组件是强依赖的。
判断配置是否存在 1 2 3 4 5 /** * @var \Hyperf\Contract\ConfigInterface */ // 通过 has(): bool 方法判断对应的 $key 值是否存在于配置中,$key 值可以通过 . 连接符定位到下级数组 $config->has($key);
环境变量 读取环境变量 1 2 3 4 // config/config.php return [ 'app_name' => env('APP_NAME', 'Hyperf Skeleton'), ];
注解 什么是注解? 什么是注释? 在解释注解之前我们需要先定义一下 注解
与 注释
的区别:
注释: 给程序员看,帮助理解代码,对代码起到解释、说明的作用。
注解: 给应用程序看,用于元数据的定义,单独使用时没有任何作用,需配合应用程序对其元数据进行利用才有作用。
注解解析如何实现? Hyperf
使用了 doctrine/annotations 包来对代码内的注解进行解析,注解必须写在下面示例的标准注释块才能被正确解析,其它格式均不能被正确解析。 注释块示例:
1 2 3 /** * @AnnotationClass() */
注解是如何发挥作用的? 我们有说到注解只是元数据的定义 ,需配合应用程序才能发挥作用,在 Hyperf
里,注解内的数据会被收集到 Hyperf\Di\Annotation\AnnotationCollector
类供应用程序使用,当然根据您的实际情况,也可以收集到您自定义的类去,随后在这些注解本身希望发挥作用的地方对已收集的注解元数据进行读取和利用,以达到期望的功能实现。
忽略某些注解 我们可以通过在 config/autoload/annotations.php
内将相关注解设置为忽略。
1 2 3 4 5 6 7 8 return [ 'scan' => [ // ignore_annotations 数组内的注解都会被注解扫描器忽略 'ignore_annotations' => [ 'mixin', ], ], ];
使用注解 注解一共有3种应用对象,分别是 类
、类方法
和 类属性
。
使用类注解 类注解定义是在 class
关键词上方的注释块内,比如常用的 @Controller
和 @AutoController
就是类注解的使用典范,下面的代码示例则为一个正确使用类注解的示例,表明 @ClassAnnotation
注解应用于 Foo
类。
1 2 3 4 /** * @ClassAnnotation() */ class Foo {}
使用类方法注解 类方法注解定义是在方法上方的注释块内,比如常用的 @RequestMapping
就是类方法注解的使用典范,下面的代码示例则为一个正确使用类方法注解的示例,表明 @MethodAnnotation
注解应用于 Foo::bar()
方法。
1 2 3 4 5 6 7 8 9 10 class Foo { /** * @MethodAnnotation() */ public function bar() { // some code } }
使用类属性注解 类属性注解定义是在属性上方的注释块内,比如常用的 @Value
和 @Inject
就是类属性注解的使用典范,下面的代码示例则为一个正确使用类属性注解的示例,表明 @PropertyAnnotation
注解应用于 Foo
类的 $bar
属性。
1 2 3 4 5 6 7 class Foo { /** * @PropertyAnnotation() */ private $bar; }
注解参数传递
传递主要的单个参数 @DemoAnnotation("value")
传递字符串参数 @DemoAnnotation(key1="value1", key2="value2")
传递数组参数 @DemoAnnotation(key={"value1", "value2"})
自定义注解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <?php namespace App\Annotation; use Hyperf\Di\Annotation\AbstractAnnotation; /** * Class Bar * @package App\Annotation * @Annotation * @Target({"METHOD", "PROPERTY"}) */ class Bar extends AbstractAnnotation { // some code } /* * * Class Foo * @package App\Annotation * @Target("CLASS") */ class Foo extends AbstractAnnotation { // some code }
注意注解类的 @Annotation
和 @Target
注解为全局注解,无需 use
其中 @Target
有如下参数:
METHOD
注解允许定义在类方法上
PROPERTY
注解允许定义在类属性上
CLASS
注解允许定义在类上
ALL
注解允许定义在任何地方
自定义注解收集器 注解的收集时具体的执行流程也是在注解类内实现的,相关的方法由 Hyperf\Di\Annotation\AnnotationInterface
约束着,该接口类要求了下面 3
个方法的实现,您可以根据自己的需求实现对应的逻辑:
public function collectClass(string $className): void;
当注解定义在类时 被扫描时会触发该方法
public function collectMethod(string $className, ?string $target): void;
当注解定义在类方法时 被扫描时会触发该方法
public function collectProperty(string $className, ?string $target): void;
当注解定义在类属性时 被扫描时会触发该方法
依赖注入 安装 该组件默认存在 hyperf-skeleton
项目中并作为主要组件存在,如希望在其它框架内使用该组件可通过下面的命令安装。
1 composer require hyperf/di
事件机制 事件模式必须基于 PSR-14 去实现。Hyperf
的事件管理器默认由 hyperf/event
实现,该组件亦可用于其它框架或应用,只需通过 Composer
将该组件引入即可。
1 composer require hyperf/event
事件模式是一种经过了充分测试的可靠机制,是一种非常适用于解耦的机制,分别存在以下 3
种角色:
事件(Event)
是传递于应用代码与 监听器(Listener)
之间的通讯对象
监听器(Listener)
是用于监听 事件(Event)
的发生的监听对象
事件调度器(EventDispatcher)
是用于触发 事件(Event)
和管理 监听器(Listener)
与 事件(Event)
之间的关系的管理者对象
常见问题 Swoole 短名未关闭
[ERROR] Swoole short name have to disable before start server, please set swoole.use_shortname = ‘Off’ into your php.ini.
1 2 3 4 5 6 7 // 这些都是错误的,注意 `大小写` 和 `引号` swoole.use_shortname = 'off' // 经测试这样也可以 swoole.use_ shortname = offswoole.use_shortname = Off // 下面的才是正确的 swoole.use_ shortname = 'Off'
不能通过全局变量获取属性参数 在 PHP-FPM
下可以通过全局变量获取到请求的参数,服务器的参数等,在 Hyperf
和 Swoole
内,都 无法 通过 $_GET
/$_POST
/$_REQUEST
/$_SESSION
/$_COOKIE
/$_SERVER
等$_
开头的变量获取到任何属性参数。
参考