Hyperf入门
概述
摘取一段Hyperf官网上对自己的描述:
Hyperf将超高速和灵活性作为自己的基因,Hyperspeed + Flexibility = Hyperf
Hyperf框架初衷是作为一个真正为PHP微服务铺路的框架。
最近公司的项目,在技术选型上采用hyperf来实现,借此机会我也体验了一把基于微服务的理念来做开发。
安装
因为还需要使用到redis、mongodb、mysql,为了方便,我是通过yaml文件来安装的,下面贴出来供大家参考:
1 version: "3" 2 3 services: 4 redis: 5 image: redis:6.2.1 6 container_name: hyperf-redis 7 restart: always 8 privileged: true 9 # environment: 10 # - TZ=Asia/Shanghai 11 ports: 12 - "26379:6379" 13 networks: 14 internal: 15 ipv4_address: 172.25.2.2 16 mysql: 17 image: mariadb:10.3.28 18 container_name: hyperf-mysql 19 restart: always 20 privileged: true 21 environment: 22 MYSQL_ROOT_PASSWORD: "123456" 23 ports: 24 - "23306:3306" 25 volumes: 26 - /root/hyperf/data/mysql:/var/lib/mysql:rw 27 networks: 28 internal: 29 ipv4_address: 172.25.2.3 30 mongo: 31 image: mongo:4.4 32 container_name: hyperf-mongo 33 restart: always 34 privileged: true 35 # environment: 36 # MONGO_INITDB_ROOT_USERNAME: 'root' 37 # MONGO_INITDB_ROOT_PASSWORD: '123456' 38 ports: 39 - "27017:27017" 40 volumes: 41 - /root/hyperf/data/mongo:/data/db:rw 42 networks: 43 internal: 44 ipv4_address: 172.25.2.4 45 hyperf: 46 image: 569529989/hyperf:7.3-alpine-v3.11-swoole-mongo 47 container_name: hyperf-skeleton 48 privileged: true 49 environment: 50 - APP_PROJECT=hyperf 51 - APP_ENV=test 52 ports: 53 - "29501:9501" 54 volumes: 55 - /root/hyperf/data/project:/data/project 56 networks: 57 internal: 58 ipv4_address: 172.25.2.5 59 tty: true 60 entrypoint: 61 - /bin/sh 62 # depends_on: 63 # - mysql 64 # - mongo 65 # - redis 66 networks: 67 internal: 68 driver: bridge 69 ipam: 70 config: 71 - subnet: 172.25.2.0/24
有一点要说明的是:
因为hyperf官方的镜像:hyperf/hyperf:7.4-alpine-v3.11-swoole,这个PHP镜像中安装的扩展很少,主要是为了减少镜像的大小。
但是我们日常使用php,会用到很多初始镜像内不存在的扩展,比如我这里还需要用到mongodb扩展。于是我在官方的镜像基础上打的包 +mongo扩展,制作了一个新的镜像。
目录结构
1、整体结构
2、配置文件结构
那么是如何读取配置呢?
config/config.php中
1 <?php 2 3 declare(strict_types=1); 4 use HyperfContractStdoutLoggerInterface; 5 use PsrLogLogLevel; 6 7 return [ 8 'app_name' => env('APP_NAME', 'skeleton'), 9 'app' => [ 10 'name_space' => env('NAME_SPACE', 'AppController') 11 ], 12 ]; 13 14 15 // 读取配置的其中一种方式为:config('app.name_space')
如果上面的文件绝对路径为:config/autoload/client.php,那么获取的代码为:config('client.app.name_space')
3、app的目录结构
微服务
这里有一个原则:
所有调用的服务都应该放在 service 里面去调用 ,而不是在控制器里面直接调用 model或者logic,也不是在中间件里面直接调用model或者logic
下面贴一段示例代码:
AuthServiceInterface.php
1 <?php 2 namespace AppServiceV1Auth; 3 4 5 interface AuthServiceInterface 6 { 7 // 鉴权 8 public function checkAccess(string $route, int $uid): array; 9 10 // 获取所有定义的路由 11 public function getAllDefRoute(): array; 12 13 // 系统权限添加入库 14 public function refreshItem(): array; 15 16 // 获取所有的角色/路由/权限列表 17 public function getItemList(array $data): array; 18 }
AuthService.php
1 <?php 2 3 namespace AppServiceV1Auth; 4 5 use AppLogicAuthLogic; 6 use HyperfRpcServerAnnotationRpcService; 7 8 /** 9 * @RpcService(name="AuthService", protocol="jsonrpc", server="jsonrpc") 10 * 11 * Class AuthService 12 * @package AppServiceV1 13 */ 14 class AuthService implements AuthServiceInterface 15 { 16 // 鉴权 17 public function checkAccess(string $route, int $uid): array 18 { 19 return AuthLogic::checkAccess($route, $uid); 20 } 21 22 // 角色/权限-增加 23 public function addItem(array $data): array 24 { 25 return AuthLogic::addItem($data); 26 } 27 28 // 角色/权限-删除 29 public function deleteItem(string $name): array 30 { 31 return AuthLogic::deleteItem($name); 32 } 33 } 34
服务的调用,参考下面代码:
1 <?php 2 3 declare(strict_types=1); 4 5 namespace AppMiddleware; 6 7 class CheckLoginMiddleware implements MiddlewareInterface 8 { 9 // ... 10 11 // 鉴权 12 public function checkAccess($uid, $path) 13 { 14 $authService = new AuthService(); 15 $accessRes = $authService->checkAccess($path, $uid); 16 return $accessRes; 17 } 18 }
中间件
config/autoload/middlewares.php中
说明:比如项目的需求是先检查是否有登录权限,才去进行参数校验,就需要把登录中间件放到参数校验中间件前面去。
表单请求验证
对于复杂的验证场景,我们可以创建一个 表单请求(FormRequest),表单请求是包含验证逻辑的一个自定义请求类。
啥也不说了,直接贴代码:
控制器 AuthController.php中
1 <?php 2 3 declare(strict_types=1); 4 5 namespace AppControllerV1; 6 7 use AppConstantsErrorCode; 8 9 10 /** 11 * 权限操作模块 12 * Class AuthController 13 * @package AppControllerV1 14 */ 15 class AuthController extends AbstractController 16 { 17 // ... 18 19 /** 20 * 给角色添加路由/权限 21 * @param AuthChildRequest $validator 22 * @return array 23 */ 24 public function addChild(AuthChildRequest $validator) 25 { 26 // 参数校验 27 $validatedData = $validator->validated(); 28 29 // 限流 防止恶意请求 30 $uid = $this->request->getAttribute('uid'); 31 $res = $this->rateLimit(__FUNCTION__ . '_' . $uid); 32 if ($res['code'] != 0) { 33 return $res; 34 } 35 // ... 36 }
表单验证类 AuthChildRequest.php
1 <?php 2 3 declare(strict_types=1); 4 5 namespace AppRequestAuth; 6 7 use HyperfValidationRequestFormRequest; 8 9 class AuthChildRequest extends FormRequest 10 { 11 /** 12 * Determine if the user is authorized to make this request. 13 */ 14 public function authorize(): bool 15 { 16 return true; 17 } 18 19 /** 20 * Get custom attributes for validator errors. 21 */ 22 public function attributes(): array 23 { 24 return [ 25 'parent' => '角色', 26 'child' => '路由', 27 ]; 28 } 29 30 /** 31 * Get the validation rules that apply to the request. 32 */ 33 public function rules(): array 34 { 35 return [ 36 'parent' => 'required|string|max:255', 37 'child' => 'required|string', // 多个之间用英文逗号隔开 38 ]; 39 } 40 41 /** 42 * 获取已定义验证规则的错误消息 43 */ 44 public function messages(): array 45 { 46 return [ 47 'required' => ':attribute必填', 48 ]; 49 } 50 }
参考链接:
https://hyperf.wiki/2.1/#/