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 Hyperf\Contract\StdoutLoggerInterface; 5 use Psr\Log\LogLevel; 6 7 return [ 8 'app_name' => env('APP_NAME', 'skeleton'), 9 'app' => [ 10 'name_space' => env('NAME_SPACE', 'App\Controller') 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 App\Service\V1\Auth; 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 App\Service\V1\Auth; 4 5 use App\Logic\AuthLogic; 6 use Hyperf\RpcServer\Annotation\RpcService; 7 8 /** 9 * @RpcService(name="AuthService", protocol="jsonrpc", server="jsonrpc") 10 * 11 * Class AuthService 12 * @package App\Service\V1 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 App\Middleware; 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 App\Controller\V1; 6 7 use App\Constants\ErrorCode; 8 9 10 /** 11 * 權限操作模塊 12 * Class AuthController 13 * @package App\Controller\V1 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 App\Request\Auth; 6 7 use Hyperf\Validation\Request\FormRequest; 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/#/