mirror of
https://gitee.com/hyperf/hyperf.git
synced 2024-11-29 18:27:44 +08:00
Update docs and translate (#5262)
This commit is contained in:
parent
67ad6b7250
commit
18f5fba851
@ -403,7 +403,7 @@ class DebugCommand extends HyperfCommand
|
||||
|
||||
# 运行命令
|
||||
|
||||
!> 注意:在运行命令时,默认不会触发事件分发,可通过添加 `--enable-event-dispatcher` 参数来开启。
|
||||
!> 注意:在运行命令时,默认会触发事件分发,可通过添加 `--disable-event-dispatcher` 参数来开启。
|
||||
|
||||
## 命令行中运行
|
||||
|
||||
|
@ -153,12 +153,12 @@ class DemoConsumer extends ConsumerMessage
|
||||
}
|
||||
```
|
||||
|
||||
### 禁止消費進程自啟
|
||||
### 禁止消費進程自啓
|
||||
|
||||
默認情況下,使用了 `@Consumer` 註解後,框架會自動創建子進程啟動消費者,並且會在子進程異常退出後,重新拉起。
|
||||
默認情況下,使用了 `@Consumer` 註解後,框架會自動創建子進程啓動消費者,並且會在子進程異常退出後,重新拉起。
|
||||
如果出於開發階段,進行消費者調試時,可能會因為消費其他消息而導致調試不便。
|
||||
|
||||
這種情況,只需要在 `@Consumer` 註解中配置 `enable=false` (默認為 `true` 跟隨服務啟動)或者在對應的消費者中重寫類方法 `isEnable()` 返回 `false` 即可
|
||||
這種情況,只需要在 `@Consumer` 註解中配置 `enable=false` (默認為 `true` 跟隨服務啓動)或者在對應的消費者中重寫類方法 `isEnable()` 返回 `false` 即可
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -190,7 +190,7 @@ class DemoConsumer extends ConsumerMessage
|
||||
|
||||
### 設置最大消費數
|
||||
|
||||
可以修改 `@Consumer` 註解中的 `maxConsumption` 屬性,設置此消費者最大處理的消息數,達到指定消費數後,消費者進程會重啟。
|
||||
可以修改 `@Consumer` 註解中的 `maxConsumption` 屬性,設置此消費者最大處理的消息數,達到指定消費數後,消費者進程會重啓。
|
||||
|
||||
### 消費結果
|
||||
|
||||
|
@ -117,8 +117,8 @@ class Foo extends AbstractAnnotation
|
||||
- `public function collectMethod(string $className, ?string $target): void;` 當註解定義在類方法時被掃描時會觸發該方法
|
||||
- `public function collectProperty(string $className, ?string $target): void` 當註解定義在類屬性時被掃描時會觸發該方法
|
||||
|
||||
因為框架實現了註解收集器緩存功能,所以需要您將自定義收集器配置到 `annotations.scan.collectors` 中,這樣框架才能自動緩存收集好的註解,在下次啟動時進行復用。
|
||||
如果沒有配置對應的收集器,就會導致自定義註解只有在首次啟動 `server` 時生效,而再次啟動時不會生效。
|
||||
因為框架實現了註解收集器緩存功能,所以需要您將自定義收集器配置到 `annotations.scan.collectors` 中,這樣框架才能自動緩存收集好的註解,在下次啓動時進行復用。
|
||||
如果沒有配置對應的收集器,就會導致自定義註解只有在首次啓動 `server` 時生效,而再次啓動時不會生效。
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
@ -6,7 +6,7 @@ AOP 為 `Aspect Oriented Programming` 的縮寫,意為:`面向切面編程`
|
||||
|
||||
用通俗的話來講,就是在 Hyperf 裏可以通過 `切面(Aspect)` 介入到任意類的任意方法的執行流程中去,從而改變或加強原方法的功能,這就是 AOP。
|
||||
|
||||
> 注意這裏所指的任意類並不是完全意義上的所有類,在 Hyperf 啟動初期用於實現 AOP 功能的類自身不能被切入。
|
||||
> 注意這裏所指的任意類並不是完全意義上的所有類,在 Hyperf 啓動初期用於實現 AOP 功能的類自身不能被切入。
|
||||
|
||||
## 介紹
|
||||
|
||||
@ -100,8 +100,8 @@ class FooAspect extends AbstractAspect
|
||||
|
||||
## 代理類緩存
|
||||
|
||||
所有被 AOP 影響的類,都會在 `./runtime/container/proxy/` 文件夾內生成對應的 `代理類緩存`,是否在啟動時自動生成取決於 `config/config.php` 配置文件中 `scan_cacheable` 配置項的值,默認值為 `false`,如果該配置項為 `true` 則 Hyperf 不會掃描和生成代理類緩存,而是直接以現有的緩存文件作為最終的代理類。如果該配置項為 `false`,則 Hyperf 會在每次啟動應用時掃描註解掃描域並自動的生成對應的代理類緩存,當代碼發生變化時,代理類緩存也會自動的重新生成。
|
||||
所有被 AOP 影響的類,都會在 `./runtime/container/proxy/` 文件夾內生成對應的 `代理類緩存`,是否在啓動時自動生成取決於 `config/config.php` 配置文件中 `scan_cacheable` 配置項的值,默認值為 `false`,如果該配置項為 `true` 則 Hyperf 不會掃描和生成代理類緩存,而是直接以現有的緩存文件作為最終的代理類。如果該配置項為 `false`,則 Hyperf 會在每次啓動應用時掃描註解掃描域並自動的生成對應的代理類緩存,當代碼發生變化時,代理類緩存也會自動的重新生成。
|
||||
|
||||
通常在開發環境下,該值為 `false`,這樣更便於開發調試,而在部署生產環境時,我們可能會希望 Hyperf 提前將所有代理類提前生成,而不是使用時動態的生成,可以通過 `php bin/hyperf.php` 命令來生成所有代理類,然後再通過環境變量 `SCAN_CACHEABLE` 為 `true` 修改該配置項的值,以達到啟動時間更短、應用內存佔用更低的目的。
|
||||
通常在開發環境下,該值為 `false`,這樣更便於開發調試,而在部署生產環境時,我們可能會希望 Hyperf 提前將所有代理類提前生成,而不是使用時動態的生成,可以通過 `php bin/hyperf.php` 命令來生成所有代理類,然後再通過環境變量 `SCAN_CACHEABLE` 為 `true` 修改該配置項的值,以達到啓動時間更短、應用內存佔用更低的目的。
|
||||
|
||||
基於以上,如果您使用 Docker 或 Kubernetes 等虛擬化技術來部署您的應用的話,您可以在鏡像構建階段就生成對應的代理類緩存並寫入到鏡像中去,在運行鏡像實例時,可大大減少啟動時間和應用內存。
|
||||
基於以上,如果您使用 Docker 或 Kubernetes 等虛擬化技術來部署您的應用的話,您可以在鏡像構建階段就生成對應的代理類緩存並寫入到鏡像中去,在運行鏡像實例時,可大大減少啓動時間和應用內存。
|
||||
|
@ -24,7 +24,7 @@ composer require hyperf/async-queue
|
||||
| handle_timeout | int | 10 | 消息處理超時時間 |
|
||||
| processes | int | 1 | 消費進程數 |
|
||||
| concurrent.limit | int | 1 | 同時處理消息數 |
|
||||
| max_messages | int | 0 | 進程重啟所需最大處理的消息數 默認不重啟 |
|
||||
| max_messages | int | 0 | 進程重啓所需最大處理的消息數 默認不重啓 |
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -74,7 +74,7 @@ return [
|
||||
|
||||
```mermaid
|
||||
graph LR;
|
||||
A[服務啟動]-->B[異步消費進程啟動]
|
||||
A[服務啓動]-->B[異步消費進程啓動]
|
||||
B-->C[監聽隊列]
|
||||
D[投遞任務]-->C
|
||||
C-->F[消費任務]
|
||||
@ -350,7 +350,7 @@ class QueueController extends AbstractController
|
||||
|
||||
### QueueLengthListener
|
||||
|
||||
框架自帶了一個記錄隊列長度的監聽器,默認不開啟,您如果需要,可以自行添加到 `listeners` 配置中。
|
||||
框架自帶了一個記錄隊列長度的監聽器,默認不開啓,您如果需要,可以自行添加到 `listeners` 配置中。
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -364,8 +364,8 @@ return [
|
||||
|
||||
### ReloadChannelListener
|
||||
|
||||
當消息執行超時,或項目重啟導致消息執行被中斷,最終都會被移動到 `timeout` 隊列中,只要您可以保證消息執行是冪等的(同一個消息執行一次,或執行多次,最終表現一致),
|
||||
就可以開啟以下監聽器,框架會自動將 `timeout` 隊列中消息移動到 `waiting` 隊列中,等待下次消費。
|
||||
當消息執行超時,或項目重啓導致消息執行被中斷,最終都會被移動到 `timeout` 隊列中,只要您可以保證消息執行是冪等的(同一個消息執行一次,或執行多次,最終表現一致),
|
||||
就可以開啓以下監聽器,框架會自動將 `timeout` 隊列中消息移動到 `waiting` 隊列中,等待下次消費。
|
||||
|
||||
> 監聽器監聽 `QueueLength` 事件,默認執行 500 次消息後觸發一次。
|
||||
|
||||
|
@ -102,7 +102,7 @@
|
||||
## 文檔生成
|
||||
|
||||
- [hyperf/swagger](https://github.com/hyperf/swagger) Hyperf 官方提供的 Swagger 文檔自動生成組件 (beta)
|
||||
- [tangwei/swagger](https://github.com/tw2066/api-docs) 一個基於 PHP 類型(DTO)自動生成 swagger 文檔組件,啟動自動掃描、自動生成路由(UI)、註解驗證
|
||||
- [tangwei/swagger](https://github.com/tw2066/api-docs) 一個基於 PHP 類型(DTO)自動生成 swagger 文檔組件,啓動自動掃描、自動生成路由(UI)、註解驗證
|
||||
|
||||
## Graphql
|
||||
|
||||
@ -122,7 +122,7 @@
|
||||
|
||||
- [hyperf/swoole-tracker](https://github.com/hyperf/swoole-tracker) Hyperf 官方提供的對接 Swoole Tracker 的組件,提供阻塞分析、性能分析、內存泄漏分析、運行狀態及調用統計等功能
|
||||
- [hyperf/task](https://github.com/hyperf/task) Hyperf 官方提供的 Task 組件,對 Swoole 的 Task 機制進行了封裝及抽象,提供便捷的註解用法
|
||||
- [hyperf/gotask](https://github.com/hyperf/gotask) GoTask 通過 Swoole 進程管理功能啟動 Go 進程作為 Swoole 主進程邊車(Sidecar),利用進程通訊將任務投遞給邊車處理並接收返回值。可以理解為 Go 版的 Swoole TaskWorker。
|
||||
- [hyperf/gotask](https://github.com/hyperf/gotask) GoTask 通過 Swoole 進程管理功能啓動 Go 進程作為 Swoole 主進程邊車(Sidecar),利用進程通訊將任務投遞給邊車處理並接收返回值。可以理解為 Go 版的 Swoole TaskWorker。
|
||||
|
||||
## 開發調試
|
||||
|
||||
|
@ -124,7 +124,7 @@
|
||||
- [#4449](https://github.com/hyperf/hyperf/pull/4449) 為 `Hyperf\Utils\Collection` 增加多條件排序的能力。
|
||||
- [#4455](https://github.com/hyperf/hyperf/pull/4455) 新增命令 `gen:view-engine-cache` 可以預生成模板緩存,避免併發帶來的一系列問題。
|
||||
- [#4453](https://github.com/hyperf/hyperf/pull/4453) 新增 `Hyperf\Tracer\Aspect\ElasticserachAspect`,用來記錄 `elasticsearch` 客户端的調用記錄。
|
||||
- [#4458](https://github.com/hyperf/hyperf/pull/4458) 新增 `Hyperf\Di\ScanHandler\ProcScanHandler`,用來支持 `Windows` + `Swow` 環境下啟動服務。
|
||||
- [#4458](https://github.com/hyperf/hyperf/pull/4458) 新增 `Hyperf\Di\ScanHandler\ProcScanHandler`,用來支持 `Windows` + `Swow` 環境下啓動服務。
|
||||
|
||||
# v2.2.22 - 2022-01-04
|
||||
|
||||
@ -157,7 +157,7 @@
|
||||
|
||||
## 優化
|
||||
|
||||
- [#4350](https://github.com/hyperf/hyperf/pull/4350) 優化了未開啟 `swoole.use_shortname` 時的錯誤信息。
|
||||
- [#4350](https://github.com/hyperf/hyperf/pull/4350) 優化了未開啓 `swoole.use_shortname` 時的錯誤信息。
|
||||
- [#4360](https://github.com/hyperf/hyperf/pull/4360) 將 `Hyperf\Amqp\IO\SwooleIO` 進行重構,使用更加穩定和高效的 `Swoole\Coroutine\Socket` 而非 `Swoole\Coroutine\Client`。
|
||||
|
||||
# v2.2.20 - 2021-12-13
|
||||
@ -165,7 +165,7 @@
|
||||
## 修復
|
||||
|
||||
- [#4338](https://github.com/hyperf/hyperf/pull/4338) 修復使用單測客户端時,路徑中帶有參數會導致無法正確匹配路由的問題。
|
||||
- [#4346](https://github.com/hyperf/hyperf/pull/4346) 修復使用組件 `php-amqplib/php-amqplib:3.1.1` 時,啟動報錯的問題。
|
||||
- [#4346](https://github.com/hyperf/hyperf/pull/4346) 修復使用組件 `php-amqplib/php-amqplib:3.1.1` 時,啓動報錯的問題。
|
||||
|
||||
## 新增
|
||||
|
||||
@ -235,7 +235,7 @@
|
||||
|
||||
## 修復
|
||||
|
||||
- [#4171](https://github.com/hyperf/hyperf/pull/4171) 修復使用 `consul` 組件時,開啟 `ACL` 驗證後,健康檢測失敗的問題。
|
||||
- [#4171](https://github.com/hyperf/hyperf/pull/4171) 修復使用 `consul` 組件時,開啓 `ACL` 驗證後,健康檢測失敗的問題。
|
||||
- [#4188](https://github.com/hyperf/hyperf/pull/4188) 修復使用 `composer 1.x` 版本時,打包 `phar` 失敗的問題。
|
||||
|
||||
# v2.2.13 - 2021-10-25
|
||||
@ -304,7 +304,7 @@
|
||||
## 修復
|
||||
|
||||
- [#4028](https://github.com/hyperf/hyperf/pull/4028) 修復 `grafana` 面板中,請求數結果計算錯誤的問題。
|
||||
- [#4030](https://github.com/hyperf/hyperf/pull/4030) 修復異步隊列會因為解壓縮模型失敗,導致進程中斷隨後重啟的問題。
|
||||
- [#4030](https://github.com/hyperf/hyperf/pull/4030) 修復異步隊列會因為解壓縮模型失敗,導致進程中斷隨後重啓的問題。
|
||||
- [#4042](https://github.com/hyperf/hyperf/pull/4042) 修復因 `SocketIO` 服務關閉時清理過期的 `fd`,進而導致協程死鎖的問題。
|
||||
|
||||
## 新增
|
||||
@ -340,12 +340,12 @@
|
||||
|
||||
- [#3969](https://github.com/hyperf/hyperf/pull/3969) 修復 PHP8 環境下使用 `Hyperf\Validation\Rules\Unique::__toString()` 導致類型錯誤的問題。
|
||||
- [#3979](https://github.com/hyperf/hyperf/pull/3979) 修復熔斷器組件,`timeout` 變量無法使用的問題。
|
||||
- [#3986](https://github.com/hyperf/hyperf/pull/3986) 修復文件系統組件,開啟 `SWOOLE_HOOK_NATIVE_CURL` 後導致 OSS hook 失敗的問題。
|
||||
- [#3986](https://github.com/hyperf/hyperf/pull/3986) 修復文件系統組件,開啓 `SWOOLE_HOOK_NATIVE_CURL` 後導致 OSS hook 失敗的問題。
|
||||
|
||||
## 新增
|
||||
|
||||
- [#3987](https://github.com/hyperf/hyperf/pull/3987) AMQP 組件支持延時隊列。
|
||||
- [#3989](https://github.com/hyperf/hyperf/pull/3989) [#3992](https://github.com/hyperf/hyperf/pull/3992) 為熱更新組件新增了配置 `command`,可以用來定義自己的啟動腳本,支持 [nano](https://github.com/hyperf/nano) 組件。
|
||||
- [#3989](https://github.com/hyperf/hyperf/pull/3989) [#3992](https://github.com/hyperf/hyperf/pull/3992) 為熱更新組件新增了配置 `command`,可以用來定義自己的啓動腳本,支持 [nano](https://github.com/hyperf/nano) 組件。
|
||||
|
||||
# v2.2.5 - 2021-08-23
|
||||
|
||||
@ -366,7 +366,7 @@
|
||||
|
||||
## 修復
|
||||
|
||||
- [#3925](https://github.com/hyperf/hyperf/pull/3925) 修復 `Nacos` 開啟 `light beat` 功能後,心跳失敗的問題。
|
||||
- [#3925](https://github.com/hyperf/hyperf/pull/3925) 修復 `Nacos` 開啓 `light beat` 功能後,心跳失敗的問題。
|
||||
- [#3926](https://github.com/hyperf/hyperf/pull/3926) 修復配置項 `config_center.drivers.nacos.client` 無法正常工作的問題。
|
||||
|
||||
## 新增
|
||||
@ -387,7 +387,7 @@
|
||||
- [#3897](https://github.com/hyperf/hyperf/pull/3897) 修復因為 `lightBeatEnabled` 導致心跳失敗,進而導致 `Nacos` 服務註冊多次的問題。
|
||||
- [#3905](https://github.com/hyperf/hyperf/pull/3905) 修復 `AMQP` 連接在關閉時導致空指針的問題。
|
||||
- [#3906](https://github.com/hyperf/hyperf/pull/3906) 修復 `AMQP` 連接關閉時,因已經銷燬所有等待通道而導致失敗的問題。
|
||||
- [#3908](https://github.com/hyperf/hyperf/pull/3908) 修復使用了以 `CoordinatorManager` 為基礎的循環邏輯時,自定義進程無法正常重啟的問題。
|
||||
- [#3908](https://github.com/hyperf/hyperf/pull/3908) 修復使用了以 `CoordinatorManager` 為基礎的循環邏輯時,自定義進程無法正常重啓的問題。
|
||||
|
||||
# v2.2.2 - 2021-08-03
|
||||
|
||||
@ -484,7 +484,7 @@
|
||||
|
||||
## 新增
|
||||
|
||||
- [#3329](https://github.com/hyperf/hyperf/pull/3329) `@Crontab` 註解的 `enable` 參數增加支持設置數組, 你可以通過它動態的控制定時任務是否啟動。
|
||||
- [#3329](https://github.com/hyperf/hyperf/pull/3329) `@Crontab` 註解的 `enable` 參數增加支持設置數組, 你可以通過它動態的控制定時任務是否啓動。
|
||||
|
||||
# v2.1.16 - 2021-04-26
|
||||
|
||||
@ -677,9 +677,9 @@
|
||||
|
||||
- [#3165](https://github.com/hyperf/hyperf/pull/3165) 修復方法 `Hyperf\Database\Schema\MySqlBuilder::getColumnListing` 在 `MySQL 8.0` 版本中無法正常使用的問題。
|
||||
- [#3174](https://github.com/hyperf/hyperf/pull/3174) 修復 `hyperf/database` 組件中 `where` 語句因為不嚴謹的代碼編寫,導致被綁定參數會被惡意替換的問題。
|
||||
- [#3179](https://github.com/hyperf/hyperf/pull/3179) 修復 `json-rpc` 客户端因對端服務重啟,導致接收數據一直異常的問題。
|
||||
- [#3179](https://github.com/hyperf/hyperf/pull/3179) 修復 `json-rpc` 客户端因對端服務重啓,導致接收數據一直異常的問題。
|
||||
- [#3189](https://github.com/hyperf/hyperf/pull/3189) 修復 `kafka` 在集羣模式下無法正常使用的問題。
|
||||
- [#3191](https://github.com/hyperf/hyperf/pull/3191) 修復 `json-rpc` 客户端因對端服務重啟,導致連接池中的連接全部失效,新的請求進來時,首次使用皆會報錯的問題。
|
||||
- [#3191](https://github.com/hyperf/hyperf/pull/3191) 修復 `json-rpc` 客户端因對端服務重啓,導致連接池中的連接全部失效,新的請求進來時,首次使用皆會報錯的問題。
|
||||
|
||||
## 新增
|
||||
|
||||
@ -879,7 +879,7 @@
|
||||
|
||||
## 變更
|
||||
|
||||
- [#2918](https://github.com/hyperf/hyperf/pull/2918) 當使用 `watcher` 組件時,不可以開啟 `daemonize`。
|
||||
- [#2918](https://github.com/hyperf/hyperf/pull/2918) 當使用 `watcher` 組件時,不可以開啓 `daemonize`。
|
||||
- [#2930](https://github.com/hyperf/hyperf/pull/2930) 更新 `php-amqplib` 組件最低版本由 `v2.7` 到 `v2.9.2`。
|
||||
|
||||
## 優化
|
||||
@ -892,7 +892,7 @@
|
||||
|
||||
- [#2857](https://github.com/hyperf/hyperf/pull/2857) 為 `service-governance` 組件新增 `Consul` 的 `ACL Token` 支持。
|
||||
- [#2870](https://github.com/hyperf/hyperf/pull/2870) 為腳本 `vendor:publish` 支持發佈配置目錄的能力。
|
||||
- [#2875](https://github.com/hyperf/hyperf/pull/2875) 為 `watcher` 組件新增可選項 `no-restart`,允許動態修改註解緩存,但不重啟服務。
|
||||
- [#2875](https://github.com/hyperf/hyperf/pull/2875) 為 `watcher` 組件新增可選項 `no-restart`,允許動態修改註解緩存,但不重啓服務。
|
||||
- [#2883](https://github.com/hyperf/hyperf/pull/2883) 為 `scout` 組件數據導入腳本,增加可選項 `--chunk` 和 `--column|c`,允許用户指定任一字段,進行數據插入,解決偏移量過大導致查詢效率慢的問題。
|
||||
- [#2891](https://github.com/hyperf/hyperf/pull/2891) 為 `crontab` 組件新增可用於發佈的配置文件。
|
||||
|
||||
@ -963,7 +963,7 @@
|
||||
|
||||
- [#2768](https://github.com/hyperf/hyperf/pull/2768) 修復 `WebSocket` 握手失敗時導致內存泄露的問題。
|
||||
- [#2777](https://github.com/hyperf/hyperf/pull/2777) 修復低版本 `redis` 擴展,`RedisCluster` 構造函數 `$auth` 不支持 `null`,導致報錯的問題。
|
||||
- [#2779](https://github.com/hyperf/hyperf/pull/2779) 修復因沒有設置 `translation` 配置文件導致服務啟動失敗的問題。
|
||||
- [#2779](https://github.com/hyperf/hyperf/pull/2779) 修復因沒有設置 `translation` 配置文件導致服務啓動失敗的問題。
|
||||
|
||||
## 變更
|
||||
|
||||
@ -1064,7 +1064,7 @@
|
||||
- [#2565](https://github.com/hyperf/hyperf/pull/2565) 修復生成代理類時,因為存在匿名類,導致代理類在沒有父類的情況下使用了 `parent::class` 而報錯的問題。
|
||||
- [#2578](https://github.com/hyperf/hyperf/pull/2578) 修復當自定義進程拋錯後,事件 `AfterProcessHandle` 無法被觸發的問題。
|
||||
- [#2582](https://github.com/hyperf/hyperf/pull/2582) 修復使用 `Redis::multi` 且在 `defer` 中使用了其他 `Redis` 指令後,導致 `Redis` 同時被兩個協程使用而報錯的問題。
|
||||
- [#2589](https://github.com/hyperf/hyperf/pull/2589) 修復使用了協程風格服務時,`AMQP` 消費者無法正常啟動的問題。
|
||||
- [#2589](https://github.com/hyperf/hyperf/pull/2589) 修復使用了協程風格服務時,`AMQP` 消費者無法正常啓動的問題。
|
||||
- [#2590](https://github.com/hyperf/hyperf/pull/2590) 修復使用了協程風格服務時,`Crontab` 無法正常工作的問題。
|
||||
|
||||
## 優化
|
||||
@ -1138,7 +1138,7 @@
|
||||
## 新增
|
||||
|
||||
- [#2331](https://github.com/hyperf/hyperf/pull/2331) [hyperf/nacos](https://github.com/hyperf/nacos) 組件增加授權接口。
|
||||
- [#2331](https://github.com/hyperf/hyperf/pull/2331) [hyperf/nacos](https://github.com/hyperf/nacos) 組件增加 `nacos.enable` 配置,用於控制是否啟用 `Nacos` 服務。
|
||||
- [#2331](https://github.com/hyperf/hyperf/pull/2331) [hyperf/nacos](https://github.com/hyperf/nacos) 組件增加 `nacos.enable` 配置,用於控制是否啓用 `Nacos` 服務。
|
||||
- [#2331](https://github.com/hyperf/hyperf/pull/2331) [hyperf/nacos](https://github.com/hyperf/nacos) 組件增加配置合併類型,默認使用全量覆蓋。
|
||||
- [#2377](https://github.com/hyperf/hyperf/pull/2377) 為 gRPC 客户端 的 request 增加 `ts` 請求頭,以兼容 Node.js gRPC server 等。
|
||||
- [#2384](https://github.com/hyperf/hyperf/pull/2384) 新增助手函數 `optional()`,以創建 `Hyperf\Utils\Optional` 對象或更方便 Optional 的使用。
|
||||
@ -1146,7 +1146,7 @@
|
||||
## 修改
|
||||
|
||||
- [#2331](https://github.com/hyperf/hyperf/pull/2331) 修復 [hyperf/nacos](https://github.com/hyperf/nacos) 組件,服務或配置不存在時,會拋出異常的問題。
|
||||
- [#2356](https://github.com/hyperf/hyperf/pull/2356) [#2368](https://github.com/hyperf/hyperf/pull/2368) 修復 `pid_file` 被用户修改後,命令行 `server:start` 啟動失敗的問題。
|
||||
- [#2356](https://github.com/hyperf/hyperf/pull/2356) [#2368](https://github.com/hyperf/hyperf/pull/2368) 修復 `pid_file` 被用户修改後,命令行 `server:start` 啓動失敗的問題。
|
||||
- [#2358](https://github.com/hyperf/hyperf/pull/2358) 修復驗證器規則 `digits` 不支持 `int` 類型的問題。
|
||||
|
||||
## 優化
|
||||
@ -1183,8 +1183,8 @@
|
||||
|
||||
- [#2275](https://github.com/hyperf/hyperf/pull/2275) 修復配置中心,拉取配置進程會出現阻塞的 BUG。
|
||||
- [#2276](https://github.com/hyperf/hyperf/pull/2276) 修復 `Apollo` 配置中心,當配置沒有變更時,會清除所有本地配置項的 BUG。
|
||||
- [#2280](https://github.com/hyperf/hyperf/pull/2280) 修復 `Interface` 的方法會被 `AOP` 重寫,導致啟動報錯的 BUG。
|
||||
- [#2281](https://github.com/hyperf/hyperf/pull/2281) 當使用 `Task` 組件,且沒有啟動協程時,`Signal` 組件會導致啟動報錯的 BUG。
|
||||
- [#2280](https://github.com/hyperf/hyperf/pull/2280) 修復 `Interface` 的方法會被 `AOP` 重寫,導致啓動報錯的 BUG。
|
||||
- [#2281](https://github.com/hyperf/hyperf/pull/2281) 當使用 `Task` 組件,且沒有啓動協程時,`Signal` 組件會導致啓動報錯的 BUG。
|
||||
- [#2304](https://github.com/hyperf/hyperf/pull/2304) 修復當使用 `SocketIOServer` 的內存適配器,刪除 `sid` 時,會導致死循環的 BUG。
|
||||
- [#2309](https://github.com/hyperf/hyperf/pull/2309) 修復 `JsonRpcHttpTransporter` 無法設置自定義超時時間的 BUG。
|
||||
|
||||
@ -1305,13 +1305,13 @@
|
||||
## 新增
|
||||
|
||||
- [#1934](https://github.com/hyperf/hyperf/pull/1934) 增加腳本 `gen:constant` 用於創建常量類。
|
||||
- [#1982](https://github.com/hyperf/hyperf/pull/1982) 添加熱更新組件,文件修改後自動收集註解,自動重啟。
|
||||
- [#1982](https://github.com/hyperf/hyperf/pull/1982) 添加熱更新組件,文件修改後自動收集註解,自動重啓。
|
||||
|
||||
## 修復
|
||||
|
||||
- [#1952](https://github.com/hyperf/hyperf/pull/1952) 修復數據庫遷移類存在時,也會生成同類名類,導致類名衝突的 BUG。
|
||||
- [#1960](https://github.com/hyperf/hyperf/pull/1960) 修復 `Hyperf\HttpServer\ResponseEmitter::isMethodsExists()` 判斷錯誤的 BUG。
|
||||
- [#1961](https://github.com/hyperf/hyperf/pull/1961) 修復因文件 `config/autoload/aspects.php` 不存在導致服務無法啟動的 BUG。
|
||||
- [#1961](https://github.com/hyperf/hyperf/pull/1961) 修復因文件 `config/autoload/aspects.php` 不存在導致服務無法啓動的 BUG。
|
||||
- [#1964](https://github.com/hyperf/hyperf/pull/1964) 修復接口請求時,數據體為空會導致 `500` 錯誤的 BUG。
|
||||
- [#1965](https://github.com/hyperf/hyperf/pull/1965) 修復 `initRequestAndResponse` 失敗後,會導致請求狀態碼與實際不符的 BUG。
|
||||
- [#1968](https://github.com/hyperf/hyperf/pull/1968) 修復當修改 `aspects.php` 文件後,`Aspect` 無法安裝修改後的結果運行的 BUG。
|
||||
@ -1334,7 +1334,7 @@
|
||||
## 主要功能
|
||||
|
||||
1. 重構 [hyperf/di](https://github.com/hyperf/di) 組件,特別是對 AOP 和註解的優化,在 2.0 版本,該組件使用了一個全新的加載機制來提供 AOP 功能的支持。
|
||||
1. 對比 1.x 版本來説最顯著的一個功能就是現在你可以通過 AOP 功能切入任何方式實例化的一個類了,比如説,在 1.x 版本,你只能切入由 DI 容器創建的類,你無法切入一個由 `new` 關鍵詞實例化的類,但在 2.0 版本都可以生效了。不過仍有一些例外的情況,您仍無法切入那些在啟動階段用來提供 AOP 功能的類;
|
||||
1. 對比 1.x 版本來説最顯著的一個功能就是現在你可以通過 AOP 功能切入任何方式實例化的一個類了,比如説,在 1.x 版本,你只能切入由 DI 容器創建的類,你無法切入一個由 `new` 關鍵詞實例化的類,但在 2.0 版本都可以生效了。不過仍有一些例外的情況,您仍無法切入那些在啓動階段用來提供 AOP 功能的類;
|
||||
2. 在 1.x 版本,AOP 只能作用於普通的類,無法支持 `Final` 類,但在 2.0 版本您可以這麼做了;
|
||||
3. 在 1.x 版本,您無法在當前類的構造函數中使用 `@Inject` 或 `@Value` 註解標記的類成員屬性的值,但在 2.0 版本里,您可以這麼做了;
|
||||
4. 在 1.x 版本,只有通過 DI 容器創建的對象才能使 `@Inject` 和 `@Value` 註解的功能生效,通過 `new` 關鍵詞創建的對象無法生效,但在 2.0 版本,都可以生效了;
|
||||
@ -1443,7 +1443,7 @@ return [
|
||||
- [#1743](https://github.com/hyperf/hyperf/pull/1743) 修復 `grafana.json` 中錯誤的`refId` 字段值;
|
||||
- [#1748](https://github.com/hyperf/hyperf/pull/1748) 修復 `hyperf/amqp` 組件在使用其他連接池時,對應的 `concurrent.limit` 配置不生效的問題;
|
||||
- [#1750](https://github.com/hyperf/hyperf/pull/1750) 修復連接池組件,在連接關閉失敗時會導致計數有誤的問題;
|
||||
- [#1754](https://github.com/hyperf/hyperf/pull/1754) 修復 BASE Server 服務,啟動提示沒有考慮 UDP 服務的情況;
|
||||
- [#1754](https://github.com/hyperf/hyperf/pull/1754) 修復 BASE Server 服務,啓動提示沒有考慮 UDP 服務的情況;
|
||||
- [#1764](https://github.com/hyperf/hyperf/pull/1764) 修復當時間值為 null 時,datatime 驗證器執行失敗的 BUG;
|
||||
- [#1769](https://github.com/hyperf/hyperf/pull/1769) 修復 `hyperf/socketio-server` 組件中,客户端初始化斷開連接操作時會報 Notice 的錯誤的問題;
|
||||
|
||||
@ -1558,7 +1558,7 @@ return [
|
||||
|
||||
- [#1501](https://github.com/hyperf/hyperf/pull/1501) 添加 `Symfony` 命令行事件觸發器,使之可以與 `hyperf/event` 組件結合使用;
|
||||
- [#1502](https://github.com/hyperf/hyperf/pull/1502) 為註解 `Hyperf\AsyncQueue\Annotation\AsyncQueueMessage` 添加 `maxAttempts` 參數,用於控制消息失敗時重複消費的次數;
|
||||
- [#1510](https://github.com/hyperf/hyperf/pull/1510) 添加 `Hyperf/Utils/CoordinatorManager`,用於提供更優雅的啟動和停止服務,服務啟動前不響應請求,服務停止前,保證某些循環邏輯能夠正常結束;
|
||||
- [#1510](https://github.com/hyperf/hyperf/pull/1510) 添加 `Hyperf/Utils/CoordinatorManager`,用於提供更優雅的啓動和停止服務,服務啓動前不響應請求,服務停止前,保證某些循環邏輯能夠正常結束;
|
||||
- [#1517](https://github.com/hyperf/hyperf/pull/1517) 為依賴注入容器的懶加載功能添加了對接口繼承和抽象方法繼承的支持;
|
||||
- [#1529](https://github.com/hyperf/hyperf/pull/1529) 處理 `response cookies` 中的 `SameSite` 屬性;
|
||||
|
||||
@ -1585,14 +1585,14 @@ return [
|
||||
|
||||
- [#1471](https://github.com/hyperf/hyperf/pull/1471) 修復 `NSQ` 組件,數據量超過 `max-output-buffer-size` 接收數據失敗的 `BUG`;
|
||||
- [#1472](https://github.com/hyperf/hyperf/pull/1472) 修復 `NSQ` 組件,在消費者中發佈消息時,會導致消費者無法正常消費的 `BUG`;
|
||||
- [#1474](https://github.com/hyperf/hyperf/pull/1474) 修復 `NSQ` 組件,`requeue` 消息時,消費者會意外重啟的 `BUG`;
|
||||
- [#1474](https://github.com/hyperf/hyperf/pull/1474) 修復 `NSQ` 組件,`requeue` 消息時,消費者會意外重啓的 `BUG`;
|
||||
- [#1477](https://github.com/hyperf/hyperf/pull/1477) 修復使用 `Hyperf\Testing\Client::flushContext` 時,會引發 `Fixed Invalid argument supplied` 異常的 `BUG`;
|
||||
|
||||
# v1.1.22 - 2020-03-26
|
||||
|
||||
## 新增
|
||||
|
||||
- [#1440](https://github.com/hyperf/hyperf/pull/1440) 為 NSQ 的每個連接新增 `enable` 配置項來控制連接下的所有消費者的自啟功能;
|
||||
- [#1440](https://github.com/hyperf/hyperf/pull/1440) 為 NSQ 的每個連接新增 `enable` 配置項來控制連接下的所有消費者的自啓功能;
|
||||
- [#1451](https://github.com/hyperf/hyperf/pull/1451) 新增 Filesystem 組件;
|
||||
- [#1459](https://github.com/hyperf/hyperf/pull/1459) 模型 Collection 新增 macroable 支持;
|
||||
- [#1463](https://github.com/hyperf/hyperf/pull/1463) 為 Guzzle Handler 增加 `on_stats` 選項的功能支持;
|
||||
@ -1613,16 +1613,16 @@ return [
|
||||
## 新增
|
||||
|
||||
- [#1393](https://github.com/hyperf/hyperf/pull/1393) 為 `Hyperf\HttpMessage\Stream\SwooleStream` 實現更多的方法;
|
||||
- [#1419](https://github.com/hyperf/hyperf/pull/1419) 允許 ConfigFetcher 通過一個協程啟動而無需額外啟動一個進程;
|
||||
- [#1419](https://github.com/hyperf/hyperf/pull/1419) 允許 ConfigFetcher 通過一個協程啓動而無需額外啓動一個進程;
|
||||
- [#1424](https://github.com/hyperf/hyperf/pull/1424) 允許用户通過配置文件的形式修改 `session_name` 配置;
|
||||
- [#1435](https://github.com/hyperf/hyperf/pull/1435) 為模型緩存增加 `use_default_value` 屬性來自動修正緩存數據與數據庫數據之間的差異;
|
||||
- [#1436](https://github.com/hyperf/hyperf/pull/1436) 為 NSQ 消費者增加 `isEnable()` 方法來控制消費者進程是否啟用自啟功能;
|
||||
- [#1436](https://github.com/hyperf/hyperf/pull/1436) 為 NSQ 消費者增加 `isEnable()` 方法來控制消費者進程是否啓用自啓功能;
|
||||
|
||||
# v1.1.20 - 2020-03-12
|
||||
|
||||
## 新增
|
||||
|
||||
- [#1402](https://github.com/hyperf/hyperf/pull/1402) 增加 `Hyperf\DbConnection\Annotation\Transactional` 註解來自動開啟一個事務;
|
||||
- [#1402](https://github.com/hyperf/hyperf/pull/1402) 增加 `Hyperf\DbConnection\Annotation\Transactional` 註解來自動開啓一個事務;
|
||||
- [#1412](https://github.com/hyperf/hyperf/pull/1412) 增加 `Hyperf\View\RenderInterface::getContents()` 方法來直接獲取 View Render 的渲染內容;
|
||||
- [#1416](https://github.com/hyperf/hyperf/pull/1416) 增加 Swoole 事件常量 `ON_WORKER_ERROR`.
|
||||
|
||||
@ -1665,7 +1665,7 @@ return [
|
||||
|
||||
## 變更
|
||||
|
||||
- [#1324](https://github.com/hyperf/hyperf/pull/1324) [hyperf/async-queue](https://github.com/hyperf/async-queue) 組件不再提供默認啟用 `Hyperf\AsyncQueue\Listener\QueueLengthListener`;
|
||||
- [#1324](https://github.com/hyperf/hyperf/pull/1324) [hyperf/async-queue](https://github.com/hyperf/async-queue) 組件不再提供默認啓用 `Hyperf\AsyncQueue\Listener\QueueLengthListener`;
|
||||
|
||||
## 優化
|
||||
|
||||
@ -1680,7 +1680,7 @@ return [
|
||||
|
||||
## 新增
|
||||
|
||||
- [#1220](https://github.com/hyperf/hyperf/pull/1220) 為 Apollo 組件增加 BootProcessListener 來實現在服務啟動時從 Apollo 拉取配置的功能;
|
||||
- [#1220](https://github.com/hyperf/hyperf/pull/1220) 為 Apollo 組件增加 BootProcessListener 來實現在服務啓動時從 Apollo 拉取配置的功能;
|
||||
- [#1292](https://github.com/hyperf/hyperf/pull/1292) 為 `Hyperf\Database\Schema\Blueprint::foreign()` 方法的返回類型增加了 `Hyperf\Database\Schema\ForeignKeyDefinition` 類型;
|
||||
- [#1313](https://github.com/hyperf/hyperf/pull/1313) 為 `hyperf\crontab` 組件增加了 Command 模式支持;
|
||||
- [#1321](https://github.com/hyperf/hyperf/pull/1321) 增加 [hyperf/nsq](https://github.com/hyperf/nsq) 組件,[NSQ](https://nsq.io) 是一個實時的分佈式消息平台;
|
||||
@ -1703,7 +1703,7 @@ return [
|
||||
## 修復
|
||||
|
||||
- [#1262](https://github.com/hyperf/hyperf/pull/1262) 修復 keepaliveIO 功能下 socket 會被消耗光的問題;
|
||||
- [#1266](https://github.com/hyperf/hyperf/pull/1266) 修復當自定義進程存在 Timer 的情況下會無法重啟的問題;
|
||||
- [#1266](https://github.com/hyperf/hyperf/pull/1266) 修復當自定義進程存在 Timer 的情況下會無法重啓的問題;
|
||||
- [#1272](https://github.com/hyperf/hyperf/pull/1272) 修復 JSONRPC 下當 Request ID 為 null 時檢查會失敗的問題;
|
||||
|
||||
## 優化
|
||||
@ -1734,7 +1734,7 @@ return [
|
||||
- [#1208](https://github.com/hyperf/hyperf/pull/1208) 為 JSON-RPC 的響應增加了 `error.data.code` 值來傳遞 Exception Code;
|
||||
- [#1208](https://github.com/hyperf/hyperf/pull/1208) 為 `Hyperf\Rpc\Contract\TransporterInterface` 增加了 `recv` 方法;
|
||||
- [#1215](https://github.com/hyperf/hyperf/pull/1215) 新增 [hyperf/super-globals](https://github.com/hyperf/super-globals) 組件,用來適配一些不支持 PSR-7 的第三方包;
|
||||
- [#1219](https://github.com/hyperf/hyperf/pull/1219) 為 AMQP 消費者增加 `enable` 屬性,通過該屬性來控制該消費者是否跟隨 Server 一同啟動;
|
||||
- [#1219](https://github.com/hyperf/hyperf/pull/1219) 為 AMQP 消費者增加 `enable` 屬性,通過該屬性來控制該消費者是否跟隨 Server 一同啓動;
|
||||
|
||||
## 修復
|
||||
|
||||
@ -1747,7 +1747,7 @@ return [
|
||||
|
||||
- [#1208](https://github.com/hyperf/hyperf/pull/1208) 優化了 JSON-RPC 組件的部分邏輯;
|
||||
- [#1174](https://github.com/hyperf/hyperf/pull/1174) 調整了 `Hyperf\Utils\Parallel` 在輸出異常時的格式,現在會一同打印 Trace 信息;
|
||||
- [#1224](https://github.com/hyperf/hyperf/pull/1224) 允許 Aliyun ACM 配置中心的配置獲取進程解析 UTF-8 字符,同時在 Worker 啟動後會自動獲取一次配置,以及拉取的配置現在會傳遞到自定義進程了;
|
||||
- [#1224](https://github.com/hyperf/hyperf/pull/1224) 允許 Aliyun ACM 配置中心的配置獲取進程解析 UTF-8 字符,同時在 Worker 啓動後會自動獲取一次配置,以及拉取的配置現在會傳遞到自定義進程了;
|
||||
- [#1235](https://github.com/hyperf/hyperf/pull/1235) 在 AMQP 生產者執行 declare 後釋放對應的連接;
|
||||
|
||||
## 修改
|
||||
@ -1815,7 +1815,7 @@ return [
|
||||
|
||||
- [#1104](https://github.com/hyperf/hyperf/pull/1104) 修復了 Guzzle 客户端的重試中間件的狀態碼識別範圍為 2xx;
|
||||
- [#1105](https://github.com/hyperf/hyperf/pull/1105) 修復了 Retry 組件在重試嘗試前不還原管道堆棧的問題;
|
||||
- [#1106](https://github.com/hyperf/hyperf/pull/1106) 修復了數據庫在開啟 `sticky` 模式時連接回歸連接池時沒有重置狀態的問題;
|
||||
- [#1106](https://github.com/hyperf/hyperf/pull/1106) 修復了數據庫在開啓 `sticky` 模式時連接回歸連接池時沒有重置狀態的問題;
|
||||
- [#1119](https://github.com/hyperf/hyperf/pull/1119) 修復 TCP 協議下的 JSONRPC Server 在解析 JSON 失敗時無法正確的返回預期的 Error Response 的問題;
|
||||
- [#1124](https://github.com/hyperf/hyperf/pull/1124) 修復 Session 中間件在儲存當前的 URL 時,當 URL 以 `/` 結尾時會忽略斜槓的問題;
|
||||
|
||||
@ -1919,13 +1919,13 @@ return [
|
||||
- [#906](https://github.com/hyperf/hyperf/pull/906) 修復 `Hyperf\HttpMessage\Server\Request` 端口獲取有誤的 BUG;
|
||||
- [#907](https://github.com/hyperf/hyperf/pull/907) 修復 `Nats` 組件 `requestSync` 方法,超時時間不準確的 BUG;
|
||||
- [#909](https://github.com/hyperf/hyperf/pull/909) 修復 `Parallel` 內邏輯拋錯後,無法正常停止的 BUG;
|
||||
- [#925](https://github.com/hyperf/hyperf/pull/925) 修復因 `Socket` 無法正常建立,導致進程頻繁重啟的 BUG;
|
||||
- [#925](https://github.com/hyperf/hyperf/pull/925) 修復因 `Socket` 無法正常建立,導致進程頻繁重啓的 BUG;
|
||||
- [#932](https://github.com/hyperf/hyperf/pull/932) 修復 `Translator::setLocale` 在協程環境下,數據混淆的 BUG;
|
||||
- [#940](https://github.com/hyperf/hyperf/pull/940) 修復 `WebSocketClient::push` 方法 `finish` 參數類型錯誤;
|
||||
|
||||
## 優化
|
||||
|
||||
- [#907](https://github.com/hyperf/hyperf/pull/907) 優化 `Nats` 消費者頻繁重啟;
|
||||
- [#907](https://github.com/hyperf/hyperf/pull/907) 優化 `Nats` 消費者頻繁重啓;
|
||||
- [#928](https://github.com/hyperf/hyperf/pull/928) `Hyperf\ModelCache\Cacheable::query` 批量修改數據時,可以刪除對應緩存;
|
||||
- [#936](https://github.com/hyperf/hyperf/pull/936) 優化調用模型緩存 `increment` 時,可能因併發情況導致的數據有錯;
|
||||
|
||||
@ -1944,7 +1944,7 @@ return [
|
||||
|
||||
## 修復
|
||||
|
||||
- [#831](https://github.com/hyperf/hyperf/pull/831) 修復 Redis 客户端連接在 Redis Server 重啟後不會自動重連的問題;
|
||||
- [#831](https://github.com/hyperf/hyperf/pull/831) 修復 Redis 客户端連接在 Redis Server 重啓後不會自動重連的問題;
|
||||
- [#835](https://github.com/hyperf/hyperf/pull/835) 修復 `Request::inputs` 方法的默認值參數與預期效果不一致的問題;
|
||||
- [#841](https://github.com/hyperf/hyperf/pull/841) 修復數據庫遷移在多數據庫的情況下連接無效的問題;
|
||||
- [#844](https://github.com/hyperf/hyperf/pull/844) 修復 Composer 閲讀器不支持根命名空間的用法的問題;
|
||||
@ -1963,7 +1963,7 @@ return [
|
||||
|
||||
- [#778](https://github.com/hyperf/hyperf/pull/778) `Hyperf\Testing\Client` 新增 `PUT` 和 `DELETE`方法;
|
||||
- [#784](https://github.com/hyperf/hyperf/pull/784) 新增服務監控組件;
|
||||
- [#795](https://github.com/hyperf/hyperf/pull/795) `AbstractProcess` 增加 `restartInterval` 參數,允許子進程異常或正常退出後,延遲重啟;
|
||||
- [#795](https://github.com/hyperf/hyperf/pull/795) `AbstractProcess` 增加 `restartInterval` 參數,允許子進程異常或正常退出後,延遲重啓;
|
||||
- [#804](https://github.com/hyperf/hyperf/pull/804) `Command` 增加事件 `BeforeHandle` `AfterHandle` 和 `FailToHandle`;
|
||||
|
||||
## 變更
|
||||
@ -1975,14 +1975,14 @@ return [
|
||||
|
||||
- [#779](https://github.com/hyperf/hyperf/pull/779) 修復 `JPG` 文件驗證不通過的問題;
|
||||
- [#787](https://github.com/hyperf/hyperf/pull/787) 修復 `db:seed` 參數 `--class` 多餘,導致報錯的問題;
|
||||
- [#795](https://github.com/hyperf/hyperf/pull/795) 修復自定義進程在異常拋出後,無法正常重啟的 BUG;
|
||||
- [#796](https://github.com/hyperf/hyperf/pull/796) 修復 `etcd` 配置中心 `enable` 即時設為 `false`,在項目啟動時,依然會拉取配置的 BUG;
|
||||
- [#795](https://github.com/hyperf/hyperf/pull/795) 修復自定義進程在異常拋出後,無法正常重啓的 BUG;
|
||||
- [#796](https://github.com/hyperf/hyperf/pull/796) 修復 `etcd` 配置中心 `enable` 即時設為 `false`,在項目啓動時,依然會拉取配置的 BUG;
|
||||
|
||||
## 優化
|
||||
|
||||
- [#781](https://github.com/hyperf/hyperf/pull/781) 可以根據國際化組件配置發佈驗證器語言包到規定位置;
|
||||
- [#796](https://github.com/hyperf/hyperf/pull/796) 優化 `ETCD` 客户端,不會多次創建 `HandlerStack`;
|
||||
- [#797](https://github.com/hyperf/hyperf/pull/797) 優化子進程重啟
|
||||
- [#797](https://github.com/hyperf/hyperf/pull/797) 優化子進程重啓
|
||||
|
||||
# v1.1.3 - 2019-10-24
|
||||
|
||||
@ -2016,9 +2016,9 @@ return [
|
||||
|
||||
- [#694](https://github.com/hyperf-cloud/hyperf/pull/694) 修復 `Hyperf\Validation\Request\FormRequest` 的 `validationData` 方法不包含上傳的文件的問題;
|
||||
- [#700](https://github.com/hyperf-cloud/hyperf/pull/700) 修復 `Hyperf\HttpServer\Contract\ResponseInterface` 的 `download` 方法不能按預期運行的問題;
|
||||
- [#701](https://github.com/hyperf-cloud/hyperf/pull/701) 修復自定義進程在出現未捕獲的異常時不會自動重啟的問題;
|
||||
- [#701](https://github.com/hyperf-cloud/hyperf/pull/701) 修復自定義進程在出現未捕獲的異常時不會自動重啓的問題;
|
||||
- [#704](https://github.com/hyperf-cloud/hyperf/pull/704) 修復 `Hyperf\Validation\Middleware\ValidationMiddleware` 在 action 參數沒有定義參數類型時會報錯的問題;
|
||||
- [#713](https://github.com/hyperf-cloud/hyperf/pull/713) 修復當開啟了註解緩存功能是,`ignoreAnnotations` 不能按預期工作的問題;
|
||||
- [#713](https://github.com/hyperf-cloud/hyperf/pull/713) 修復當開啓了註解緩存功能是,`ignoreAnnotations` 不能按預期工作的問題;
|
||||
- [#717](https://github.com/hyperf-cloud/hyperf/pull/717) 修復 `getValidatorInstance` 方法會重複創建驗證器對象的問題;
|
||||
- [#724](https://github.com/hyperf-cloud/hyperf/pull/724) 修復 `db:seed` 命令在沒有傳 `database` 參數時會報錯的問題;
|
||||
- [#729](https://github.com/hyperf-cloud/hyperf/pull/729) 修正組件配置項 `db:model` 為 `gen:model`;
|
||||
@ -2029,7 +2029,7 @@ return [
|
||||
## Fixed
|
||||
|
||||
- [#664](https://github.com/hyperf/hyperf/pull/664) 調整通過 `gen:request` 命令生成 FormRequest 時 `authorize` 方法的默認返回值;
|
||||
- [#665](https://github.com/hyperf/hyperf/pull/665) 修復啟動時永遠會自動生成代理類的問題;
|
||||
- [#665](https://github.com/hyperf/hyperf/pull/665) 修復啓動時永遠會自動生成代理類的問題;
|
||||
- [#667](https://github.com/hyperf/hyperf/pull/667) 修復當訪問一個不存在的路由時 `Hyperf\Validation\Middleware\ValidationMiddleware` 會拋出異常的問題;
|
||||
- [#672](https://github.com/hyperf/hyperf/pull/672) 修復當 Action 方法上的參數類型為非對象類型時 `Hyperf\Validation\Middleware\ValidationMiddleware` 會拋出一個未捕獲的異常的問題;
|
||||
- [#674](https://github.com/hyperf/hyperf/pull/674) 修復使用 `gen:model` 命令從數據庫生成模型時模型表名錯誤的問題;
|
||||
@ -2052,7 +2052,7 @@ return [
|
||||
- [#597](https://github.com/hyperf/hyperf/pull/597) 為 AsyncQueue 組件的消費者增加 `Concurrent` 來控制消費速率;
|
||||
- [#599](https://github.com/hyperf/hyperf/pull/599) 為 AsyncQueue 組件的消費者增加根據當前重試次數來設定該消息的重試等待時長的功能,可以為消息設置階梯式的重試等待;
|
||||
- [#619](https://github.com/hyperf/hyperf/pull/619) 為 Guzzle 客户端增加 HandlerStackFactory 類,以便更便捷地創建一個 HandlerStack;
|
||||
- [#620](https://github.com/hyperf/hyperf/pull/620) 為 AsyncQueue 組件的消費者增加自動重啟的機制;
|
||||
- [#620](https://github.com/hyperf/hyperf/pull/620) 為 AsyncQueue 組件的消費者增加自動重啓的機制;
|
||||
- [#629](https://github.com/hyperf/hyperf/pull/629) 允許通過配置文件的形式為 Apollo 客户端定義 `clientIp`, `pullTimeout`, `intervalTimeout` 配置;
|
||||
- [#647](https://github.com/hyperf/hyperf/pull/647) 根據 server 的配置,自動為 TCP Response 追加 `eof`;
|
||||
- [#648](https://github.com/hyperf/hyperf/pull/648) 為 AMQP Consumer 增加 `nack` 的返回類型,當消費邏輯返回 `Hyperf\Amqp\Result::NACK` 時抽象消費者會以 `basic_nack` 方法來響應消息;
|
||||
@ -2132,7 +2132,7 @@ Config Provider 內數據結構的變化:
|
||||
|
||||
## 修復
|
||||
|
||||
- [#448](https://github.com/hyperf/hyperf/pull/448) 修復了當 HTTP Server 或 WebSocket Server 存在時,TCP Server 有可能無法啟動的問題;
|
||||
- [#448](https://github.com/hyperf/hyperf/pull/448) 修復了當 HTTP Server 或 WebSocket Server 存在時,TCP Server 有可能無法啓動的問題;
|
||||
- [#623](https://github.com/hyperf/hyperf/pull/623) 修復了當傳遞一個 `null` 值到代理類的方法參數時,方法仍然會獲取方法默認值的問題;
|
||||
|
||||
# v1.0.16 - 2019-09-20
|
||||
@ -2162,7 +2162,7 @@ Config Provider 內數據結構的變化:
|
||||
- [#541](https://github.com/hyperf/hyperf/pull/541) 修復 gRPC 客户端的 `$client` 參數設置錯誤的問題;
|
||||
- [#542](https://github.com/hyperf/hyperf/pull/542) 修復 `Hyperf\Grpc\Parser::parseResponse` 無法支持 gRPC 標準狀態碼的問題;
|
||||
- [#551](https://github.com/hyperf/hyperf/pull/551) 修復當服務端關閉了 gRPC 連接時,gRPC 客户端會殘留一個死循環的協程;
|
||||
- [#558](https://github.com/hyperf/hyperf/pull/558) 修復 `UDP Server` 無法正確配置啟動的問題;
|
||||
- [#558](https://github.com/hyperf/hyperf/pull/558) 修復 `UDP Server` 無法正確配置啓動的問題;
|
||||
|
||||
## 優化
|
||||
|
||||
@ -2297,7 +2297,7 @@ Config Provider 內數據結構的變化:
|
||||
- [#300](https://github.com/hyperf/hyperf/pull/300) 讓 AsyncQueue 的消息於子協程內來進行處理,修復 `attempts` 參數與實際重試次數不一致的問題;
|
||||
- [#305](https://github.com/hyperf/hyperf/pull/305) 修復 `Hyperf\Utils\Arr::set` 方法的 `$key` 參數不支持 `int` 個 `null` 的問題;
|
||||
- [#312](https://github.com/hyperf/hyperf/pull/312) 修復 `Hyperf\Amqp\BeforeMainServerStartListener` 監聽器的優先級錯誤的問題;
|
||||
- [#315](https://github.com/hyperf/hyperf/pull/315) 修復 ETCD 配置中心在 Worker 進程重啟後或在自定義進程內無法使用問題;
|
||||
- [#315](https://github.com/hyperf/hyperf/pull/315) 修復 ETCD 配置中心在 Worker 進程重啓後或在自定義進程內無法使用問題;
|
||||
- [#318](https://github.com/hyperf/hyperf/pull/318) 修復服務會持續註冊到服務中心的問題;
|
||||
|
||||
## 變更
|
||||
@ -2410,7 +2410,7 @@ Config Provider 內數據結構的變化:
|
||||
## 新增
|
||||
|
||||
- [#48](https://github.com/hyperf/hyperf/pull/48) 增加 WebSocket 協程客户端及服務端
|
||||
- [#51](https://github.com/hyperf/hyperf/pull/51) 增加了 `enableCache` 參數去控制 `DefinitionSource` 是否啟用註解掃描緩存
|
||||
- [#51](https://github.com/hyperf/hyperf/pull/51) 增加了 `enableCache` 參數去控制 `DefinitionSource` 是否啓用註解掃描緩存
|
||||
- [#61](https://github.com/hyperf/hyperf/pull/61) 通過 `db:model` 命令創建模型時增加屬性類型
|
||||
- [#65](https://github.com/hyperf/hyperf/pull/65) 模型緩存增加 JSON 格式支持
|
||||
|
||||
@ -2420,7 +2420,7 @@ Config Provider 內數據結構的變化:
|
||||
|
||||
## 修復
|
||||
|
||||
- [#45](https://github.com/hyperf/hyperf/pull/55) 修復當引用了 `hyperf/websocket-server` 組件時有可能會導致 HTTP Server 啟動失敗的問題
|
||||
- [#45](https://github.com/hyperf/hyperf/pull/55) 修復當引用了 `hyperf/websocket-server` 組件時有可能會導致 HTTP Server 啓動失敗的問題
|
||||
- [#55](https://github.com/hyperf/hyperf/pull/55) 修復方法級別的 `@Middleware` 註解可能會被覆蓋的問題
|
||||
- [#73](https://github.com/hyperf/hyperf/pull/73) 修復 `db:model` 命令對短屬性處理不正確的問題
|
||||
- [#88](https://github.com/hyperf/hyperf/pull/88) 修復當控制器存在多層文件夾時生成的路由可能不正確的問題
|
||||
|
@ -403,7 +403,7 @@ class DebugCommand extends HyperfCommand
|
||||
|
||||
# 運行命令
|
||||
|
||||
!> 注意:在運行命令時,默認不會觸發事件分發,可通過添加 `--enable-event-dispatcher` 參數來開啟。
|
||||
!> 注意:在運行命令時,默認會觸發事件分發,可通過添加 `--disable-event-dispatcher` 參數來開啓。
|
||||
|
||||
## 命令行中運行
|
||||
|
||||
|
@ -4,7 +4,7 @@ ConfigProvider 機制對於 Hyperf 組件化來説是個非常重要的機制,
|
||||
|
||||
# 什麼是 ConfigProvider 機制 ?
|
||||
|
||||
簡單來説,就是每個組件都會提供一個 `ConfigProvider`,通常是在組件的根目錄提供一個 `ConfigProvider` 的類,`ConfigProvider` 會提供對應組件的所有配置信息,這些信息都會被 Hyperf 框架在啟動時加載,最終`ConfigProvider` 內的配置信息會被合併到 `Hyperf\Contract\ConfigInterface` 對應的實現類去,從而實現各個組件在 Hyperf 框架下使用時要進行的配置初始化。
|
||||
簡單來説,就是每個組件都會提供一個 `ConfigProvider`,通常是在組件的根目錄提供一個 `ConfigProvider` 的類,`ConfigProvider` 會提供對應組件的所有配置信息,這些信息都會被 Hyperf 框架在啓動時加載,最終`ConfigProvider` 內的配置信息會被合併到 `Hyperf\Contract\ConfigInterface` 對應的實現類去,從而實現各個組件在 Hyperf 框架下使用時要進行的配置初始化。
|
||||
|
||||
`ConfigProvider` 本身不具備任何依賴,不繼承任何的抽象類和不要求實現任何的接口,只需提供一個 `__invoke` 方法並返回一個對應配置結構的數組即可。
|
||||
|
||||
|
@ -13,7 +13,7 @@ Hyperf 為您提供了分佈式系統的外部化配置支持,默認適配了:
|
||||
隨着業務的發展,微服務架構的升級,服務的數量、應用的配置日益增多(各種微服務、各種服務器地址、各種參數),傳統的配置文件方式和數據庫的方式已經可能無法滿足開發人員對配置管理的要求,同時對於配置的管理可能還會牽涉到 ACL 權限管理、配置版本管理和回滾、格式驗證、配置灰度發佈、集羣配置隔離等問題,以及:
|
||||
|
||||
- 安全性:配置跟隨源代碼保存在版本管理系統中,容易造成配置泄漏
|
||||
- 時效性:修改配置,需要每台服務器每個應用修改並重啟服務
|
||||
- 時效性:修改配置,需要每台服務器每個應用修改並重啓服務
|
||||
- 侷限性:無法支持動態調整,例如日誌開關、功能開關等
|
||||
|
||||
因此,我們可以通過一個配置中心以一種科學的管理方式來統一管理相關的配置。
|
||||
@ -68,7 +68,7 @@ declare(strict_types=1);
|
||||
use Hyperf\ConfigCenter\Mode;
|
||||
|
||||
return [
|
||||
// 是否開啟配置中心
|
||||
// 是否開啓配置中心
|
||||
'enable' => (bool) env('CONFIG_CENTER_ENABLE', true),
|
||||
// 使用的驅動類型,對應同級別配置 drivers 下的 key
|
||||
'driver' => env('CONFIG_CENTER_DRIVER', 'apollo'),
|
||||
@ -188,8 +188,8 @@ return [
|
||||
## 配置更新的作用範圍
|
||||
|
||||
在默認的功能實現下,是由一個 `ConfigFetcherProcess` 進程根據配置的 `interval` 來向 配置中心 Server 拉取對應 `namespace` 的配置,並通過 IPC 通訊將拉取到的新配置傳遞到各個 Worker 中,並更新到 `Hyperf\Contract\ConfigInterface` 對應的對象內。
|
||||
需要注意的是,更新的配置只會更新 `Config` 對象,故僅限應用層或業務層的配置,不涉及框架層的配置改動,因為框架層的配置改動需要重啟服務,如果您有這樣的需求,也可以通過自行實現 `ConfigFetcherProcess` 來達到目的。
|
||||
需要注意的是,更新的配置只會更新 `Config` 對象,故僅限應用層或業務層的配置,不涉及框架層的配置改動,因為框架層的配置改動需要重啓服務,如果您有這樣的需求,也可以通過自行實現 `ConfigFetcherProcess` 來達到目的。
|
||||
|
||||
## 注意事項
|
||||
|
||||
在命令行模式時,默認不會觸發事件分發,導致無法正常獲取到相關配置,可通過添加 `--enable-event-dispatcher` 參數來開啟。
|
||||
在命令行模式時,默認不會觸發事件分發,導致無法正常獲取到相關配置,可通過添加 `--enable-event-dispatcher` 參數來開啓。
|
||||
|
@ -52,12 +52,12 @@ use Hyperf\Server\Event;
|
||||
return [
|
||||
// 這裏省略了該文件的其它配置
|
||||
'settings' => [
|
||||
'enable_coroutine' => true, // 開啟內置協程
|
||||
'worker_num' => swoole_cpu_num(), // 設置啟動的 Worker 進程數
|
||||
'enable_coroutine' => true, // 開啓內置協程
|
||||
'worker_num' => swoole_cpu_num(), // 設置啓動的 Worker 進程數
|
||||
'pid_file' => BASE_PATH . '/runtime/hyperf.pid', // master 進程的 PID
|
||||
'open_tcp_nodelay' => true, // TCP 連接發送數據時會關閉 Nagle 合併算法,立即發往客户端連接
|
||||
'max_coroutine' => 100000, // 設置當前工作進程最大協程數量
|
||||
'open_http2_protocol' => true, // 啟用 HTTP2 協議解析
|
||||
'open_http2_protocol' => true, // 啓用 HTTP2 協議解析
|
||||
'max_request' => 100000, // 設置 worker 進程的最大任務數
|
||||
'socket_buffer_size' => 2 * 1024 * 1024, // 配置客户端連接的緩存區長度
|
||||
],
|
||||
@ -68,7 +68,7 @@ return [
|
||||
|
||||
如需要設置守護進程化,可在 `settings` 中增加 `'daemonize' => true`,執行 `php bin/hyperf.php start`後,程序將轉入後台作為守護進程運行
|
||||
|
||||
單獨的 Server 配置需要添加在對應 `servers` 的 `settings` 當中,如 `jsonrpc` 協議的 TCP Server 配置啟用 EOF 自動分包和設置 EOF 字符串
|
||||
單獨的 Server 配置需要添加在對應 `servers` 的 `settings` 當中,如 `jsonrpc` 協議的 TCP Server 配置啓用 EOF 自動分包和設置 EOF 字符串
|
||||
```php
|
||||
<?php
|
||||
|
||||
@ -88,7 +88,7 @@ return [
|
||||
Event::ON_RECEIVE => [\Hyperf\JsonRpc\TcpServer::class, 'onReceive'],
|
||||
],
|
||||
'settings' => [
|
||||
'open_eof_split' => true, // 啟用 EOF 自動分包
|
||||
'open_eof_split' => true, // 啓用 EOF 自動分包
|
||||
'package_eof' => "\r\n", // 設置 EOF 字符串
|
||||
],
|
||||
],
|
||||
@ -99,7 +99,7 @@ return [
|
||||
|
||||
## `config.php` 與 `autoload` 文件夾內的配置文件的關係
|
||||
|
||||
`config.php` 與 `autoload` 文件夾內的配置文件在服務啟動時都會被掃描並注入到 `Hyperf\Contract\ConfigInterface` 對應的對象中,配置的結構為一個鍵值對的大數組,兩種配置形式不同的在於 `autoload` 內配置文件的文件名會作為第一層 鍵(Key) 存在,而 `config.php` 內的則以您定義的為第一層,我們通過下面的例子來演示一下。
|
||||
`config.php` 與 `autoload` 文件夾內的配置文件在服務啓動時都會被掃描並注入到 `Hyperf\Contract\ConfigInterface` 對應的對象中,配置的結構為一個鍵值對的大數組,兩種配置形式不同的在於 `autoload` 內配置文件的文件名會作為第一層 鍵(Key) 存在,而 `config.php` 內的則以您定義的為第一層,我們通過下面的例子來演示一下。
|
||||
我們假設存在一個 `config/autoload/client.php` 文件,文件內容如下:
|
||||
```php
|
||||
return [
|
||||
@ -127,7 +127,7 @@ return [
|
||||
|
||||
### 設置配置
|
||||
|
||||
只需在 `config/config.php` 與 `config/autoload/server.php` 與 `autoload` 文件夾內的配置,都能在服務啟動時被掃描並注入到 `Hyperf\Contract\ConfigInterface` 對應的對象中,這個流程是由 `Hyperf\Config\ConfigFactory` 在 Config 對象實例化時完成的。
|
||||
只需在 `config/config.php` 與 `config/autoload/server.php` 與 `autoload` 文件夾內的配置,都能在服務啓動時被掃描並注入到 `Hyperf\Contract\ConfigInterface` 對應的對象中,這個流程是由 `Hyperf\Config\ConfigFactory` 在 Config 對象實例化時完成的。
|
||||
|
||||
### 獲取配置
|
||||
|
||||
|
@ -10,7 +10,7 @@ Hyperf 還提供了協程風格服務,此類型為單進程模型,所有的
|
||||
|
||||
## 配置
|
||||
|
||||
修改 `autoload/server.php` 配置文件,設置 `type` 為 `Hyperf\Server\CoroutineServer::class` 即可啟動協程風格。
|
||||
修改 `autoload/server.php` 配置文件,設置 `type` 為 `Hyperf\Server\CoroutineServer::class` 即可啓動協程風格。
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
@ -60,7 +60,7 @@ $db->connect($config, function ($db, $r) {
|
||||
|
||||
### 不能存在阻塞代碼
|
||||
|
||||
協程內代碼的阻塞會導致協程調度器無法切換到另一個協程繼續執行代碼,所以我們絕不能在協程內存在阻塞代碼,假設我們啟動了 `4` 個 `Worker` 來處理 `HTTP` 請求(通常啟動的 `Worker` 數量與 `CPU` 核心數一致或 `2` 倍),如果代碼中存在阻塞,暫且理論的認為每個請求都會阻塞 `1` 秒,那麼系統的 `QPS` 也將退化為 `4/s` ,這無疑就是退化成了與 `PHP-FPM` 類似的情況,所以我們絕對不能在協程中存在阻塞代碼。
|
||||
協程內代碼的阻塞會導致協程調度器無法切換到另一個協程繼續執行代碼,所以我們絕不能在協程內存在阻塞代碼,假設我們啓動了 `4` 個 `Worker` 來處理 `HTTP` 請求(通常啓動的 `Worker` 數量與 `CPU` 核心數一致或 `2` 倍),如果代碼中存在阻塞,暫且理論的認為每個請求都會阻塞 `1` 秒,那麼系統的 `QPS` 也將退化為 `4/s` ,這無疑就是退化成了與 `PHP-FPM` 類似的情況,所以我們絕對不能在協程中存在阻塞代碼。
|
||||
|
||||
那麼到底哪些是阻塞代碼呢?我們可以簡單的認為絕大多數你所熟知的非 `Swoole` 提供的異步函數的 `MySQL`、`Redis`、`Memcache`、`MongoDB`、`HTTP`、`Socket`等客户端,文件操作、`sleep/usleep` 等均為阻塞函數,這幾乎涵蓋了所有日常操作,那麼要如何解決呢?`Swoole` 提供了 `MySQL`、`PostgreSQL`、`Redis`、`HTTP`、`Socket` 的協程客户端可以使用,同時 `Swoole 4.1` 之後提供了一鍵協程化的方法 `\Swoole\Runtime::enableCoroutine()`,只需在使用協程前運行這一行代碼,`Swoole` 會將 所有使用 `php_stream` 進行 `socket` 操作均變成協程調度的異步 `I/O`,可以理解為除了 `curl` 絕大部分原生的操作都可以適用,關於此部分可查閲 [Swoole 文檔](https://wiki.swoole.com/#/runtime) 獲得更具體的信息。
|
||||
|
||||
@ -74,7 +74,7 @@ $db->connect($config, function ($db, $r) {
|
||||
對於全局變量,均是跟隨着一個 `請求(Request)` 而產生的,而 `Hyperf` 的 `請求(Request)/響應(Response)` 是由 [hyperf/http-message](https://github.com/hyperf/http-message) 通過實現 [PSR-7](https://www.php-fig.org/psr/psr-7/) 處理的,故所有的全局變量均可以在 `請求(Request)` 對象中得到相關的值;
|
||||
|
||||
對於 `global` 變量和 `static` 變量,在 `PHP-FPM` 模式下,本質都是存活於一個請求生命週期內的,而在 `Hyperf` 內因為是 `CLI` 應用,會存在 `全局週期` 和 `請求週期(協程週期)` 兩種長生命週期。
|
||||
- 全局週期,我們只需要創建一個靜態變量供全局調用即可,靜態變量意味着在服務啟動後,任意協程和代碼邏輯均共享此靜態變量內的數據,也就意味着存放的數據不能是特別服務於某一個請求或某一個協程;
|
||||
- 全局週期,我們只需要創建一個靜態變量供全局調用即可,靜態變量意味着在服務啓動後,任意協程和代碼邏輯均共享此靜態變量內的數據,也就意味着存放的數據不能是特別服務於某一個請求或某一個協程;
|
||||
- 協程週期,由於 `Hyperf` 會為每個請求自動創建一個協程來處理,那麼一個協程週期在此也可以理解為一個請求週期,在協程內,所有的狀態數據均應存放於 `Hyperf\Context\Context` 類中,通過該類的 `get`、`set` 來讀取和存儲任意結構的數據,這個 `Context(協程上下文)` 類在執行任意協程時讀取或存儲的數據都是僅限對應的協程的,同時在協程結束時也會自動銷燬相關的上下文數據。
|
||||
|
||||
### 最大協程數限制
|
||||
@ -203,7 +203,7 @@ $result = parallel([
|
||||
|
||||
#### 限制 Parallel 最大同時運行的協程數
|
||||
|
||||
當我們添加到 `Parallel` 裏的任務有很多時,假設都是一些請求任務,那麼一瞬間發出全部請求很有可能會導致對端服務因為一瞬間接收到了大量的請求而處理不過來,有宕機的風險,所以需要對對端進行適當的保護,但我們又希望可以通過 `Parallel` 機制來加速這些請求的耗時,那麼可以通過在實例化 `Parallel` 對象時傳遞第一個參數,來設置最大運行的協程數,比如我們希望最大設置的協程數為 `5` ,也就意味着 `Parallel` 裏最多隻會有 `5` 個協程在運行,只有當 `5` 個裏有協程完成結束後,後續的協程才會繼續啟動,直至所有協程完成任務,示例代碼如下:
|
||||
當我們添加到 `Parallel` 裏的任務有很多時,假設都是一些請求任務,那麼一瞬間發出全部請求很有可能會導致對端服務因為一瞬間接收到了大量的請求而處理不過來,有宕機的風險,所以需要對對端進行適當的保護,但我們又希望可以通過 `Parallel` 機制來加速這些請求的耗時,那麼可以通過在實例化 `Parallel` 對象時傳遞第一個參數,來設置最大運行的協程數,比如我們希望最大設置的協程數為 `5` ,也就意味着 `Parallel` 裏最多隻會有 `5` 個協程在運行,只有當 `5` 個裏有協程完成結束後,後續的協程才會繼續啓動,直至所有協程完成任務,示例代碼如下:
|
||||
|
||||
```php
|
||||
use Hyperf\Utils\Exception\ParallelExecutionException;
|
||||
|
@ -10,7 +10,7 @@ composer require hyperf/crontab
|
||||
|
||||
# 使用
|
||||
|
||||
## 啟動任務調度器進程
|
||||
## 啓動任務調度器進程
|
||||
|
||||
在使用定時任務組件之前,需要先在 `config/autoload/processes.php` 內註冊一下 `Hyperf\Crontab\Process\CrontabDispatcherProcess` 自定義進程,如下:
|
||||
|
||||
@ -22,13 +22,13 @@ return [
|
||||
];
|
||||
```
|
||||
|
||||
這樣服務啟動時會啟動一個自定義進程,用於對定時任務的解析和調度分發。
|
||||
同時,您還需要將 `config/autoload/crontab.php` 內的 `enable` 配置設置為 `true`,表示開啟定時任務功能,如配置文件不存在可自行創建,配置如下:
|
||||
這樣服務啓動時會啓動一個自定義進程,用於對定時任務的解析和調度分發。
|
||||
同時,您還需要將 `config/autoload/crontab.php` 內的 `enable` 配置設置為 `true`,表示開啓定時任務功能,如配置文件不存在可自行創建,配置如下:
|
||||
|
||||
```php
|
||||
<?php
|
||||
return [
|
||||
// 是否開啟定時任務
|
||||
// 是否開啓定時任務
|
||||
'enable' => true,
|
||||
];
|
||||
```
|
||||
@ -240,8 +240,8 @@ return [
|
||||
|
||||
## 運行定時任務
|
||||
|
||||
當您完成上述的配置後,以及定義了定時任務後,只需要直接啟動 `Server`,定時任務便會一同啟動。
|
||||
在您啟動後,即便您定義了足夠短週期的定時任務,定時任務也不會馬上開始執行,所有定時任務都會等到下一個分鐘週期時才會開始執行,比如您啟動的時候是 `10 時 11 分 12 秒`,那麼定時任務會在 `10 時 12 分 00 秒` 才會正式開始執行。
|
||||
當您完成上述的配置後,以及定義了定時任務後,只需要直接啓動 `Server`,定時任務便會一同啓動。
|
||||
在您啓動後,即便您定義了足夠短週期的定時任務,定時任務也不會馬上開始執行,所有定時任務都會等到下一個分鐘週期時才會開始執行,比如您啓動的時候是 `10 時 11 分 12 秒`,那麼定時任務會在 `10 時 12 分 00 秒` 才會正式開始執行。
|
||||
|
||||
### FailToExecute 事件
|
||||
|
||||
|
@ -45,7 +45,7 @@ php bin/hyperf.php vendor:publish hyperf/db
|
||||
|
||||
| 方法名 | 返回值類型 | 備註 |
|
||||
|:----------------:|:--------------:|:------------------------------------:|
|
||||
| beginTransaction | `void` | 開啟事務 支持事務嵌套 |
|
||||
| beginTransaction | `void` | 開啓事務 支持事務嵌套 |
|
||||
| commit | `void` | 提交事務 支持事務嵌套 |
|
||||
| rollBack | `void` | 回滾事務 支持事務嵌套 |
|
||||
| insert | `int` | 插入數據,返回主鍵 ID,非自增主鍵返回 0 |
|
||||
|
@ -10,14 +10,14 @@
|
||||
| :--------: | :----: |
|
||||
| Hyperf\Database\Events\QueryExecuted| Query 語句執行後 |
|
||||
| Hyperf\Database\Events\StatementPrepared| SQL 語句 prepared 後 |
|
||||
| Hyperf\Database\Events\TransactionBeginning| 事務開啟後 |
|
||||
| Hyperf\Database\Events\TransactionBeginning| 事務開啓後 |
|
||||
| Hyperf\Database\Events\TransactionCommitted| 事務提交後 |
|
||||
| Hyperf\Database\Events\TransactionRolledBack| 事務回滾後 |
|
||||
|
||||
### SQL 執行監聽器
|
||||
|
||||
根據上述的 ORM 運行事件,接下來我們來實現一個記錄 SQL 的監聽器,達到在每次執行 SQL 時記錄下來並輸出到日誌上。
|
||||
首先我們定義好 `DbQueryExecutedListener` ,實現 `Hyperf\Event\Contract\ListenerInterface` 接口並對類定義 `Hyperf\Event\Annotation\Listener` 註解,這樣 Hyperf 就會在應用啟動時自動把該監聽器註冊到事件調度器中,並在事件觸發時執行監聽邏輯,示例代碼如下:
|
||||
首先我們定義好 `DbQueryExecutedListener` ,實現 `Hyperf\Event\Contract\ListenerInterface` 接口並對類定義 `Hyperf\Event\Annotation\Listener` 註解,這樣 Hyperf 就會在應用啓動時自動把該監聽器註冊到事件調度器中,並在事件觸發時執行監聽邏輯,示例代碼如下:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
@ -134,7 +134,7 @@ return [
|
||||
|
||||
- Hyperf\Database\Commands\Ast\ModelRewriteTimestampsVisitor
|
||||
|
||||
此 `Visitor` 可以根據 `created_at` 和 `updated_at` 自動判斷,是否啟用默認記錄 `創建和修改時間` 的功能。
|
||||
此 `Visitor` 可以根據 `created_at` 和 `updated_at` 自動判斷,是否啓用默認記錄 `創建和修改時間` 的功能。
|
||||
|
||||
- Hyperf\Database\Commands\Ast\ModelRewriteGetterSetterVisitor
|
||||
|
||||
|
@ -496,10 +496,10 @@ $table->dropForeign('posts_user_id_foreign');
|
||||
$table->dropForeign(['user_id'']);
|
||||
```
|
||||
|
||||
您可以在遷移文件中使用以下方法來開啟或關閉外鍵約束:
|
||||
您可以在遷移文件中使用以下方法來開啓或關閉外鍵約束:
|
||||
|
||||
```php
|
||||
// 開啟外鍵約束
|
||||
// 開啓外鍵約束
|
||||
Schema::enableForeignKeyConstraints();
|
||||
// 禁用外鍵約束
|
||||
Schema::disableForeignKeyConstraints();
|
||||
|
@ -145,7 +145,7 @@ User::query(true)->where('gender', '>', 1)->delete();
|
||||
|
||||
當生產環境使用了模型緩存時,如果已經建立了對應緩存數據,但此時又因為邏輯變更,添加了新的字段,並且默認值不是 `0`、`空字符`、`null` 這類數據時,就會導致在數據查詢時,從緩存中查出來的數據與數據庫中的數據不一致。
|
||||
|
||||
對於這種情況,我們可以修改 `use_default_value` 為 `true`,並添加 `Hyperf\DbConnection\Listener\InitTableCollectorListener` 到 `listener.php` 配置中,使 Hyperf 應用在啟動時主動去獲取數據庫的字段信息,並在獲取緩存數據時與之比較並進行緩存數據修正。
|
||||
對於這種情況,我們可以修改 `use_default_value` 為 `true`,並添加 `Hyperf\DbConnection\Listener\InitTableCollectorListener` 到 `listener.php` 配置中,使 Hyperf 應用在啓動時主動去獲取數據庫的字段信息,並在獲取緩存數據時與之比較並進行緩存數據修正。
|
||||
|
||||
### 控制模型中緩存時間
|
||||
|
||||
|
@ -487,7 +487,7 @@ $user->delete();
|
||||
|
||||
### 通過查詢刪除模型
|
||||
|
||||
您可通過在查詢上調用 `delete` 方法來刪除模型數據,在這個例子中,我們將刪除所有 `gender` 為 `1` 的用户。與批量更新一樣,批量刪除不會為刪除的模型啟動任何模型事件:
|
||||
您可通過在查詢上調用 `delete` 方法來刪除模型數據,在這個例子中,我們將刪除所有 `gender` 為 `1` 的用户。與批量更新一樣,批量刪除不會為刪除的模型啓動任何模型事件:
|
||||
|
||||
```php
|
||||
use App\Model\User;
|
||||
@ -510,7 +510,7 @@ User::destroy([1,2,3]);
|
||||
|
||||
### 軟刪除
|
||||
|
||||
除了真實刪除數據庫記錄,`Hyperf` 也可以「軟刪除」模型。軟刪除的模型並不是真的從數據庫中刪除了。事實上,是在模型上設置了 `deleted_at` 屬性並將其值寫入數據庫。如果 `deleted_at` 值非空,代表這個模型已被軟刪除。如果要開啟模型軟刪除功能,你需要在模型上使用 `Hyperf\Database\Model\SoftDeletes` trait
|
||||
除了真實刪除數據庫記錄,`Hyperf` 也可以「軟刪除」模型。軟刪除的模型並不是真的從數據庫中刪除了。事實上,是在模型上設置了 `deleted_at` 屬性並將其值寫入數據庫。如果 `deleted_at` 值非空,代表這個模型已被軟刪除。如果要開啓模型軟刪除功能,你需要在模型上使用 `Hyperf\Database\Model\SoftDeletes` trait
|
||||
|
||||
> `SoftDeletes` trait 會自動將 `deleted_at` 屬性轉換成 `DateTime / Carbon` 實例
|
||||
|
||||
@ -565,4 +565,4 @@ class SupportMySQLBitListener implements ListenerInterface
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
```
|
||||
|
@ -148,7 +148,7 @@ return [
|
||||
|
||||
如果你想重寫主數組中的配置,只需要修改 `read` 和 `write` 數組即可。所以,這個例子中: 192.168.1.1 將作為 「讀」 連接主機,而 192.168.1.2 將作為 「寫」 連接主機。這兩個連接會共享 mysql 數組的各項配置,如數據庫的憑據(用户名 / 密碼),前綴,字符編碼等。
|
||||
|
||||
`sticky` 是一個 可選值,它可用於立即讀取在當前請求週期內已寫入數據庫的記錄。若 `sticky` 選項被啟用,並且當前請求週期內執行過 「寫」 操作,那麼任何 「讀」 操作都將使用 「寫」 連接。這樣可確保同一個請求週期內寫入的數據可以被立即讀取到,從而避免主從延遲導致數據不一致的問題。不過是否啟用它,取決於應用程序的需求。
|
||||
`sticky` 是一個 可選值,它可用於立即讀取在當前請求週期內已寫入數據庫的記錄。若 `sticky` 選項被啓用,並且當前請求週期內執行過 「寫」 操作,那麼任何 「讀」 操作都將使用 「寫」 連接。這樣可確保同一個請求週期內寫入的數據可以被立即讀取到,從而避免主從延遲導致數據不一致的問題。不過是否啓用它,取決於應用程序的需求。
|
||||
|
||||
### 多庫配置
|
||||
|
||||
@ -354,7 +354,7 @@ use Hyperf\DbConnection\Db;
|
||||
use Hyperf\Utils\Arr;
|
||||
use App\Model\Book;
|
||||
|
||||
// 啟用 SQL 數據記錄功能
|
||||
// 啓用 SQL 數據記錄功能
|
||||
Db::enableQueryLog();
|
||||
|
||||
$book = Book::query()->find(1);
|
||||
|
@ -407,7 +407,7 @@ Relation::morphMap([
|
||||
]);
|
||||
```
|
||||
|
||||
因為 `Relation::morphMap` 修改後會常駐內存,所以我們可以在項目啟動時,就創建好對應的關係映射。我們可以創建以下監聽器:
|
||||
因為 `Relation::morphMap` 修改後會常駐內存,所以我們可以在項目啓動時,就創建好對應的關係映射。我們可以創建以下監聽器:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
@ -234,7 +234,7 @@ class IndexController
|
||||
### 工廠對象注入
|
||||
|
||||
我們假設 `UserService` 的實現會更加複雜一些,在創建 `UserService` 對象時構造函數還需要傳遞進來一些非直接注入型的參數,假設我們需要從配置中取得一個值,然後 `UserService`
|
||||
需要根據這個值來決定是否開啟緩存模式(順帶一説 Hyperf 提供了更好用的 [模型緩存](zh-hk/db/model-cache.md) 功能)
|
||||
需要根據這個值來決定是否開啓緩存模式(順帶一説 Hyperf 提供了更好用的 [模型緩存](zh-hk/db/model-cache.md) 功能)
|
||||
|
||||
我們需要創建一個工廠來生成 `UserService` 對象:
|
||||
|
||||
@ -296,11 +296,11 @@ return [
|
||||
|
||||
### 懶加載
|
||||
|
||||
Hyperf 的長生命週期依賴注入在項目啟動時完成。這意味着長生命週期的類需要注意:
|
||||
Hyperf 的長生命週期依賴注入在項目啓動時完成。這意味着長生命週期的類需要注意:
|
||||
|
||||
* 構造函數時還不是協程環境,如果注入了可能會觸發協程切換的類,就會導致框架啟動失敗。
|
||||
* 構造函數時還不是協程環境,如果注入了可能會觸發協程切換的類,就會導致框架啓動失敗。
|
||||
|
||||
* 構造函數中要避免循環依賴(比較典型的例子為 `Listener` 和 `EventDispatcherInterface`),不然也會啟動失敗。
|
||||
* 構造函數中要避免循環依賴(比較典型的例子為 `Listener` 和 `EventDispatcherInterface`),不然也會啓動失敗。
|
||||
|
||||
目前解決方案是:只在實例中注入 `Psr\Container\ContainerInterface` ,而其他的組件在非構造函數執行時通過 `container` 獲取。但 PSR-11 中指出:
|
||||
|
||||
|
@ -174,4 +174,4 @@ class UserService
|
||||
|
||||
### 最好只在 `Listener` 中注入 `ContainerInterface`。
|
||||
|
||||
最好只在 `Listener` 中注入 `ContainerInterface`,而其他的組件在 `process` 中通過 `container` 獲取。框架啟動開始時,會實例化 `EventDispatcherInterface`,這個時候還不是協程環境,如果 `Listener` 中注入了可能會觸發協程切換的類,就會導致框架啟動失敗。
|
||||
最好只在 `Listener` 中注入 `ContainerInterface`,而其他的組件在 `process` 中通過 `container` 獲取。框架啓動開始時,會實例化 `EventDispatcherInterface`,這個時候還不是協程環境,如果 `Listener` 中注入了可能會觸發協程切換的類,就會導致框架啓動失敗。
|
||||
|
@ -208,7 +208,7 @@ return [
|
||||
|
||||
## 注意事項
|
||||
|
||||
1. S3 存儲請確認安裝 `hyperf/guzzle` 組件以提供協程化支持。阿里雲、七牛雲、騰訊云云存儲請[開啟 Curl Hook](/zh-hk/coroutine?id=swoole-runtime-hook-level)來使用協程。因 Curl Hook 的參數支持性問題,請使用 Swoole 4.4.13 以上版本。
|
||||
1. S3 存儲請確認安裝 `hyperf/guzzle` 組件以提供協程化支持。阿里雲、七牛雲、騰訊云云存儲請[開啓 Curl Hook](/zh-hk/coroutine?id=swoole-runtime-hook-level)來使用協程。因 Curl Hook 的參數支持性問題,請使用 Swoole 4.4.13 以上版本。
|
||||
2. minIO, ceph radosgw 等私有對象存儲方案均支持 S3 協議,可以使用 S3 適配器。
|
||||
3. 使用 Local 驅動時,根目錄是配置好的地址,而不是操作系統的根目錄。例如,Local 驅動 `root` 設置為 `/var/www`, 則本地磁盤上的 `/var/www/public/file.txt` 通過 flysystem API 訪問時應使用 `/public/file.txt` 或 `public/file.txt` 。
|
||||
4. 以阿里雲 OSS 為例,1 核 1 進程讀操作性能對比:
|
||||
@ -217,7 +217,7 @@ return [
|
||||
ab -k -c 10 -n 1000 http://127.0.0.1:9501/
|
||||
```
|
||||
|
||||
未開啟 CURL HOOK:
|
||||
未開啓 CURL HOOK:
|
||||
|
||||
```
|
||||
Concurrency Level: 10
|
||||
@ -233,7 +233,7 @@ Time per request: 202.902 [ms] (mean, across all concurrent requests)
|
||||
Transfer rate: 0.70 [Kbytes/sec] received
|
||||
```
|
||||
|
||||
開啟 CURL HOOK 後:
|
||||
開啓 CURL HOOK 後:
|
||||
|
||||
```
|
||||
Concurrency Level: 10
|
||||
|
@ -192,7 +192,7 @@ return [
|
||||
];
|
||||
```
|
||||
|
||||
配置完成後,在啟動服務時,Hyperf 會自動地將 `@RpcService` 定義了 `publishTo` 屬性為 `consul` 或 `nacos` 的服務註冊到對應的服務中心去。
|
||||
配置完成後,在啓動服務時,Hyperf 會自動地將 `@RpcService` 定義了 `publishTo` 屬性為 `consul` 或 `nacos` 的服務註冊到對應的服務中心去。
|
||||
|
||||
> 目前僅支持 `jsonrpc` 和 `jsonrpc-http` 協議發佈到服務中心去,其它協議尚未實現服務註冊
|
||||
|
||||
@ -264,7 +264,7 @@ return [
|
||||
];
|
||||
```
|
||||
|
||||
在應用啟動時會自動創建客户端類的代理對象,並在容器中使用配置項 `id` 的值(如果未設置,會使用配置項 `service` 值代替)來添加綁定關係,這樣就和手工編寫的客户端類一樣,通過注入 `CalculatorServiceInterface` 接口來直接使用客户端。
|
||||
在應用啓動時會自動創建客户端類的代理對象,並在容器中使用配置項 `id` 的值(如果未設置,會使用配置項 `service` 值代替)來添加綁定關係,這樣就和手工編寫的客户端類一樣,通過注入 `CalculatorServiceInterface` 接口來直接使用客户端。
|
||||
|
||||
> 當服務提供者使用接口類名發佈服務名,在服務消費端只需要設置配置項 `name` 值為接口類名,不需要重複設置配置項 `id` 和 `service`。
|
||||
|
||||
|
@ -217,8 +217,8 @@ class IndexController extends AbstractController
|
||||
|
||||
| 參數名 | 説明 | 默認值 |
|
||||
| --------------- | ----------------------------------------------------------------------- | ------- |
|
||||
| open | 是否開啟 SSL 傳輸加密 | `false` |
|
||||
| compression | 是否開啟壓縮 | `true` |
|
||||
| open | 是否開啓 SSL 傳輸加密 | `false` |
|
||||
| compression | 是否開啓壓縮 | `true` |
|
||||
| certFile | cert 證書存放路徑 | `''` |
|
||||
| keyFile | 私鑰存放路徑 | `''` |
|
||||
| passphrase | cert 證書密碼 | `''` |
|
||||
|
@ -3,7 +3,7 @@
|
||||
## 框架生命週期
|
||||
|
||||
Hyperf 是運行於 [Swoole](http://github.com/swoole/swoole-src) 之上的,想要理解透徹 Hyperf 的生命週期,那麼理解 [Swoole](http://github.com/swoole/swoole-src) 的生命週期也至關重要。
|
||||
Hyperf 的命令管理默認由 [symfony/console](https://github.com/symfony/console) 提供支持*(如果您希望更換該組件您也可以通過改變 skeleton 的入口文件更換成您希望使用的組件)*,在執行 `php bin/hyperf.php start` 後,將由 `Hyperf\Server\Command\StartServer` 命令類接管,並根據配置文件 `config/autoload/server.php` 內定義的 `Server` 逐個啟動。
|
||||
Hyperf 的命令管理默認由 [symfony/console](https://github.com/symfony/console) 提供支持*(如果您希望更換該組件您也可以通過改變 skeleton 的入口文件更換成您希望使用的組件)*,在執行 `php bin/hyperf.php start` 後,將由 `Hyperf\Server\Command\StartServer` 命令類接管,並根據配置文件 `config/autoload/server.php` 內定義的 `Server` 逐個啓動。
|
||||
關於依賴注入容器的初始化工作,我們並沒有由組件來實現,因為一旦交由組件來實現,這個耦合就會非常的明顯,所以在默認的情況下,是由入口文件來加載 `config/container.php` 來實現的。
|
||||
|
||||
## 請求與協程生命週期
|
||||
|
@ -148,7 +148,7 @@ class Log
|
||||
|
||||
### stdout 日誌
|
||||
|
||||
框架組件所輸出的日誌在默認情況下是由 `Hyperf\Contract\StdoutLoggerInterface` 接口的實現類 `Hyperf\Framework\Logger\StdoutLogger` 提供支持的,該實現類只是為了將相關的信息通過 `print_r()` 輸出在 `標準輸出(stdout)`,即為啟動 `Hyperf` 的 `終端(Terminal)` 上,也就意味着其實並沒有使用到 `monolog` 的,那麼如果想要使用 `monolog` 來保持一致要怎麼處理呢?
|
||||
框架組件所輸出的日誌在默認情況下是由 `Hyperf\Contract\StdoutLoggerInterface` 接口的實現類 `Hyperf\Framework\Logger\StdoutLogger` 提供支持的,該實現類只是為了將相關的信息通過 `print_r()` 輸出在 `標準輸出(stdout)`,即為啓動 `Hyperf` 的 `終端(Terminal)` 上,也就意味着其實並沒有使用到 `monolog` 的,那麼如果想要使用 `monolog` 來保持一致要怎麼處理呢?
|
||||
|
||||
是的, 還是通過強大的 `容器(Container)`.
|
||||
|
||||
|
@ -39,7 +39,7 @@ php bin/hyperf.php vendor:publish hyperf/metric
|
||||
'default' => env('METRIC_DRIVER', 'prometheus'),
|
||||
```
|
||||
|
||||
* `use_standalone_process`: 是否使用 `獨立監控進程`。推薦開啟。關閉後將在 `Worker 進程` 中處理指標收集與上報。
|
||||
* `use_standalone_process`: 是否使用 `獨立監控進程`。推薦開啓。關閉後將在 `Worker 進程` 中處理指標收集與上報。
|
||||
|
||||
```php
|
||||
'use_standalone_process' => env('TELEMETRY_USE_STANDALONE_PROCESS', true),
|
||||
@ -93,7 +93,7 @@ Prometheus 有兩種工作模式,爬模式與推模式(通過 Prometheus Pus
|
||||
|
||||
並配置爬取地址 `scrape_host`、爬取端口 `scrape_port`、爬取路徑 `scrape_path`。Prometheus 可以在對應配置下以 HTTP 訪問形式拉取全部指標。
|
||||
|
||||
> 注意:爬模式下,必須啟用獨立進程,即 use_standalone_process = true。
|
||||
> 注意:爬模式下,必須啓用獨立進程,即 use_standalone_process = true。
|
||||
|
||||
使用推模式時需設置:
|
||||
|
||||
@ -204,8 +204,8 @@ interface HistogramInterface
|
||||
|
||||
### 配置中間件
|
||||
|
||||
配置完驅動之後,只需配置一下中間件就能啟用請求 Histogram 統計功能。
|
||||
打開 `config/autoload/middlewares.php` 文件,示例為在 `http` Server 中啟用中間件。
|
||||
配置完驅動之後,只需配置一下中間件就能啓用請求 Histogram 統計功能。
|
||||
打開 `config/autoload/middlewares.php` 文件,示例為在 `http` Server 中啓用中間件。
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -321,7 +321,7 @@ class OnMetricFactoryReady implements ListenerInterface
|
||||
|
||||
> 本節只適用於 Prometheus 驅動
|
||||
|
||||
當您在使用 Prometheus 的 Histogram 時,有時會有自定義 Bucket 的需求。您可以在服務啟動前,依賴注入 Registry 並自行註冊 Histogram ,設置所需 Bucket 。稍後使用時 `MetricFactory` 就會調用您註冊好同名 Histogram 。示例如下:
|
||||
當您在使用 Prometheus 的 Histogram 時,有時會有自定義 Bucket 的需求。您可以在服務啓動前,依賴注入 Registry 並自行註冊 Histogram ,設置所需 Bucket 。稍後使用時 `MetricFactory` 就會調用您註冊好同名 Histogram 。示例如下:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -403,11 +403,11 @@ Router::get('/metrics', function(){
|
||||
|
||||
> 本節只適用於 Prometheus 驅動
|
||||
|
||||
如果您啟用了默認指標,`Hyperf/Metric` 為您準備了一個開箱即用的 Grafana 控制枱。下載控制枱 [json 文件](https://cdn.jsdelivr.net/gh/hyperf/hyperf/src/metric/grafana.json),導入 Grafana 中即可使用。
|
||||
如果您啓用了默認指標,`Hyperf/Metric` 為您準備了一個開箱即用的 Grafana 控制枱。下載控制枱 [json 文件](https://cdn.jsdelivr.net/gh/hyperf/hyperf/src/metric/grafana.json),導入 Grafana 中即可使用。
|
||||
|
||||
![grafana](imgs/grafana.png)
|
||||
|
||||
## 注意事項
|
||||
|
||||
- 如需在 `hyperf/command` 自定義命令中使用本組件收集指標,需要在啟動命令時添加命令行參數: `--enable-event-dispatcher`。
|
||||
- 如需在 `hyperf/command` 自定義命令中使用本組件收集指標,需要在啓動命令時添加命令行參數: `--enable-event-dispatcher`。
|
||||
|
||||
|
@ -33,7 +33,7 @@ $app->get('/', function () {
|
||||
$app->run();
|
||||
```
|
||||
|
||||
啟動:
|
||||
啓動:
|
||||
|
||||
```bash
|
||||
php index.php start
|
||||
@ -45,7 +45,7 @@ php index.php start
|
||||
|
||||
* 無骨架
|
||||
* 零配置
|
||||
* 快速啟動
|
||||
* 快速啓動
|
||||
* 閉包風格
|
||||
* 支持註解外的全部 Hyperf 功能
|
||||
* 兼容全部 Hyperf 組件
|
||||
|
@ -79,19 +79,19 @@ class DemoNsqConsumer extends AbstractConsumer
|
||||
}
|
||||
```
|
||||
|
||||
### 禁止消費進程自啟
|
||||
### 禁止消費進程自啓
|
||||
|
||||
默認情況下,使用了 `@Consumer` 註解定義後,框架會在啟動時自動創建子進程來啟動消費者,並且會在子進程異常退出後,自動重新拉起。但如果在處於開發階段進行某些調試工作時,可能會因為消費者的自動消費導致調試的不便。
|
||||
默認情況下,使用了 `@Consumer` 註解定義後,框架會在啓動時自動創建子進程來啓動消費者,並且會在子進程異常退出後,自動重新拉起。但如果在處於開發階段進行某些調試工作時,可能會因為消費者的自動消費導致調試的不便。
|
||||
|
||||
在這種情況下,您可通過全局關閉和局部關閉兩種形式來控制消費進程的自啟。
|
||||
在這種情況下,您可通過全局關閉和局部關閉兩種形式來控制消費進程的自啓。
|
||||
|
||||
#### 全局關閉
|
||||
|
||||
您可以在默認配置文件 `config/autoload/nsq.php` 中,將對應連接的 `enable` 選項設置為 `false`,即代表該連接下的所有消費者進程都關閉自啟功能。
|
||||
您可以在默認配置文件 `config/autoload/nsq.php` 中,將對應連接的 `enable` 選項設置為 `false`,即代表該連接下的所有消費者進程都關閉自啓功能。
|
||||
|
||||
#### 局部關閉
|
||||
|
||||
當您只需要關閉個別消費進程的自啟功能,只需要在對應的消費者中重寫父類方法 `isEnable()` 並返回 `false` 即可關閉此消費者的自啟功能;
|
||||
當您只需要關閉個別消費進程的自啓功能,只需要在對應的消費者中重寫父類方法 `isEnable()` 並返回 `false` 即可關閉此消費者的自啓功能;
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
@ -26,7 +26,7 @@ php bin/hyperf.php phar:build --name=your_project.phar
|
||||
php bin/hyperf.php phar:build --phar-version=1.0.1
|
||||
```
|
||||
|
||||
- 指定啟動文件
|
||||
- 指定啓動文件
|
||||
|
||||
```shell
|
||||
php bin/hyperf.php phar:build --bin=bin/hyperf.php
|
||||
|
@ -8,7 +8,7 @@ composer require hyperf/pool
|
||||
|
||||
## 為什麼需要連接池?
|
||||
|
||||
當併發量很低的時候,連接可以臨時建立,但當服務吞吐達到幾百、幾千的時候,頻繁 `建立連接 Connect` 和 `銷燬連接 Close` 就有可能會成為服務的一個瓶頸,那麼當服務啟動的時候,先建立好若干個連接並存放於一個隊列中,當需要使用時從隊列中取出一個並使用,使用完後再反還到隊列去,而對這個隊列數據結構進行維護的,就是連接池。
|
||||
當併發量很低的時候,連接可以臨時建立,但當服務吞吐達到幾百、幾千的時候,頻繁 `建立連接 Connect` 和 `銷燬連接 Close` 就有可能會成為服務的一個瓶頸,那麼當服務啓動的時候,先建立好若干個連接並存放於一個隊列中,當需要使用時從隊列中取出一個並使用,使用完後再反還到隊列去,而對這個隊列數據結構進行維護的,就是連接池。
|
||||
|
||||
## 使用連接池
|
||||
|
||||
@ -108,7 +108,7 @@ return [
|
||||
|
||||
當然,框架還提供了另外一種低頻組件 `ConstantFrequency`。
|
||||
|
||||
當此組件實例化後,會啟動定時器,在固定間隔調用 `Pool::flushOne(false)` 方法,此方法會拿出連接池中的一個連接,並判斷超過閒置時長後,銷燬連接。
|
||||
當此組件實例化後,會啓動定時器,在固定間隔調用 `Pool::flushOne(false)` 方法,此方法會拿出連接池中的一個連接,並判斷超過閒置時長後,銷燬連接。
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
@ -1,6 +1,6 @@
|
||||
# 自定義進程
|
||||
|
||||
[hyperf/process](https://github.com/hyperf/process) 可以添加一個用户自定義的工作進程,此函數通常用於創建一個特殊的工作進程,用於監控、上報或者其他特殊的任務。在 Server 啟動時會自動創建進程,並執行指定的子進程函數,進程意外退出時,Server 會重新拉起進程。
|
||||
[hyperf/process](https://github.com/hyperf/process) 可以添加一個用户自定義的工作進程,此函數通常用於創建一個特殊的工作進程,用於監控、上報或者其他特殊的任務。在 Server 啓動時會自動創建進程,並執行指定的子進程函數,進程意外退出時,Server 會重新拉起進程。
|
||||
|
||||
## 創建一個自定義進程
|
||||
|
||||
@ -61,9 +61,9 @@ class FooProcess extends AbstractProcess
|
||||
|
||||
> 使用 `@Process` 註解時需 `use Hyperf\Process\Annotation\Process;` 命名空間;
|
||||
|
||||
## 為進程啟動加上條件
|
||||
## 為進程啓動加上條件
|
||||
|
||||
有些時候,並不是所有時候都應該啟動一個自定義進程,一個自定義進程的啟動與否可能會根據某些配置或者某些條件來決定,我們可以通過在自定義進程類內重寫 `isEnable(): bool` 方法來實現,默認返回 `true`,即會跟隨服務一同啟動,如方法返回 `false`,則服務啟動時不會啟動該自定義進程。
|
||||
有些時候,並不是所有時候都應該啓動一個自定義進程,一個自定義進程的啓動與否可能會根據某些配置或者某些條件來決定,我們可以通過在自定義進程類內重寫 `isEnable(): bool` 方法來實現,默認返回 `true`,即會跟隨服務一同啓動,如方法返回 `false`,則服務啓動時不會啓動該自定義進程。
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -84,7 +84,7 @@ class FooProcess extends AbstractProcess
|
||||
|
||||
public function isEnable($server): bool
|
||||
{
|
||||
// 不跟隨服務啟動一同啟動
|
||||
// 不跟隨服務啓動一同啓動
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -127,7 +127,7 @@ class FooProcess extends AbstractProcess
|
||||
public int $pipeType = 2;
|
||||
|
||||
/**
|
||||
* 是否啟用協程
|
||||
* 是否啓用協程
|
||||
*/
|
||||
public bool $enableCoroutine = true;
|
||||
}
|
||||
|
@ -14,11 +14,11 @@
|
||||
|
||||
> 官方的 Dockerfile 已經完成了以下操作。
|
||||
|
||||
線上代碼部署時,請務必開啟 `scan_cacheable`。
|
||||
線上代碼部署時,請務必開啓 `scan_cacheable`。
|
||||
|
||||
開啟此配置後,首次掃描時會生成代理類和註解緩存,再次啟動時,則可以直接使用緩存,極大優化內存使用率和啟動速度。因為跳過了掃描階段,所以會依賴 `Composer Class Map`,故我們必須要執行 `--optimize-autoloader` 優化索引。
|
||||
開啓此配置後,首次掃描時會生成代理類和註解緩存,再次啓動時,則可以直接使用緩存,極大優化內存使用率和啓動速度。因為跳過了掃描階段,所以會依賴 `Composer Class Map`,故我們必須要執行 `--optimize-autoloader` 優化索引。
|
||||
|
||||
綜上,線上更新代碼,重啟項目前,需要執行以下命令
|
||||
綜上,線上更新代碼,重啓項目前,需要執行以下命令
|
||||
|
||||
```bash
|
||||
# 優化 Composer 索引
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
## 服務器要求
|
||||
|
||||
Hyperf 對系統環境有一些要求,當您使用 Swoole 網絡引擎驅動時,僅可運行於 Linux 和 Mac 環境下,但由於 Docker 虛擬化技術的發展,在 Windows 下也可以通過 Docker for Windows 來作為運行環境,通常來説 Mac 環境下,我們更推薦本地環境部署,以避免 Docker 共享磁盤緩慢導致 Hyperf 啟動速度慢的問題。當您使用 Swow 網絡引擎驅動時,則可在 Windows、Linux、Mac 下運行。
|
||||
Hyperf 對系統環境有一些要求,當您使用 Swoole 網絡引擎驅動時,僅可運行於 Linux 和 Mac 環境下,但由於 Docker 虛擬化技術的發展,在 Windows 下也可以通過 Docker for Windows 來作為運行環境,通常來説 Mac 環境下,我們更推薦本地環境部署,以避免 Docker 共享磁盤緩慢導致 Hyperf 啓動速度慢的問題。當您使用 Swow 網絡引擎驅動時,則可在 Windows、Linux、Mac 下運行。
|
||||
|
||||
[hyperf/hyperf-docker](https://github.com/hyperf/hyperf-docker) 項目內已經為您準備好了各種版本的 Dockerfile ,或直接基於已經構建好的 [hyperf/hyperf](https://hub.docker.com/r/hyperf/hyperf) 鏡像來運行。
|
||||
|
||||
@ -24,7 +24,7 @@ Hyperf 對系統環境有一些要求,當您使用 Swoole 網絡引擎驅動
|
||||
|
||||
Hyperf 使用 [Composer](https://getcomposer.org) 來管理項目的依賴,在使用 Hyperf 之前,請確保你的運行環境已經安裝好了 Composer。
|
||||
|
||||
> 安裝過程中,對於自己不清楚的選項,請直接使用回車處理,避免因自動添加了部分監聽器,但又沒有正確配置時,導致服務無法啟動的問題。
|
||||
> 安裝過程中,對於自己不清楚的選項,請直接使用回車處理,避免因自動添加了部分監聽器,但又沒有正確配置時,導致服務無法啓動的問題。
|
||||
|
||||
### 通過 `Composer` 創建項目
|
||||
|
||||
@ -44,11 +44,11 @@ composer create-project hyperf/swow-skeleton
|
||||
|
||||
假設您的本機環境並不能達到 Hyperf 的環境要求,或對於環境配置不是那麼熟悉,那麼您可以通過以下方法來運行及開發 Hyperf 項目:
|
||||
|
||||
- 啟動鏡像
|
||||
- 啓動鏡像
|
||||
|
||||
可以根據實際情況,映射到宿主機對應的目錄,以下以 `/workspace/skeleton` 為例
|
||||
|
||||
> 如果 docker 啟動時開啟了 selinux-enabled 選項,容器內訪問宿主機資源就會受限,所以啟動容器時可以增加 --privileged -u root 選項
|
||||
> 如果 docker 啓動時開啓了 selinux-enabled 選項,容器內訪問宿主機資源就會受限,所以啓動容器時可以增加 --privileged -u root 選項
|
||||
|
||||
```shell
|
||||
docker run --name hyperf \
|
||||
@ -74,7 +74,7 @@ cd /data/project
|
||||
composer create-project hyperf/hyperf-skeleton
|
||||
```
|
||||
|
||||
- 啟動項目
|
||||
- 啓動項目
|
||||
|
||||
```shell
|
||||
cd hyperf-skeleton
|
||||
@ -82,7 +82,7 @@ php bin/hyperf.php start
|
||||
```
|
||||
|
||||
接下來,就可以在宿主機 `/workspace/skeleton/hyperf-skeleton` 中看到您安裝好的代碼了。
|
||||
由於 Hyperf 是持久化的 CLI 框架,當您修改完您的代碼後,通過 `CTRL + C` 終止當前啟動的進程實例,並重新執行 `php bin/hyperf.php start` 啟動命令即可。
|
||||
由於 Hyperf 是持久化的 CLI 框架,當您修改完您的代碼後,通過 `CTRL + C` 終止當前啓動的進程實例,並重新執行 `php bin/hyperf.php start` 啓動命令即可。
|
||||
|
||||
## 存在兼容性問題的擴展
|
||||
|
||||
|
@ -214,17 +214,17 @@ class IndexController
|
||||
不過這裏的案例並未真正體現出依賴自動注入的好處及其強大之處,我們假設一下 `UserService` 也存在很多的依賴,而這些依賴同時又存在很多其它的依賴時,`new` 實例化的方式就需要手動實例化很多的對象並調整好對應的參數位,而在 `Hyperf` 裏我們就無須手動管理這些依賴,只需要聲明一下最終使用的類即可。
|
||||
而當 `UserService` 需要發生替換等劇烈的內部變化時,比如從一個本地服務替換成了一個 RPC 遠程服務,也只需要通過配置調整依賴中 `UserService` 這個鍵值對應的類為新的 RPC 服務類即可。
|
||||
|
||||
## 啟動 Hyperf 服務
|
||||
## 啓動 Hyperf 服務
|
||||
|
||||
由於 `Hyperf` 內置了協程服務器,也就意味着 `Hyperf` 將以 `CLI` 的形式去運行,所以在定義好路由及實際的邏輯代碼之後,我們需要在項目根目錄並通過命令行運行 `php bin/hyperf.php start` 來啟動服務。
|
||||
當 `Console` 界面顯示服務啟動後便可通過 `cURL` 或 瀏覽器對服務正常發起訪問了,默認服務會提供一個首頁 `http://127.0.0.1:9501/`,對於本章示例引導的情況下,也就是上面的例子所對應的訪問地址為 `http://127.0.0.1:9501/index/info?id=1`。
|
||||
由於 `Hyperf` 內置了協程服務器,也就意味着 `Hyperf` 將以 `CLI` 的形式去運行,所以在定義好路由及實際的邏輯代碼之後,我們需要在項目根目錄並通過命令行運行 `php bin/hyperf.php start` 來啓動服務。
|
||||
當 `Console` 界面顯示服務啓動後便可通過 `cURL` 或 瀏覽器對服務正常發起訪問了,默認服務會提供一個首頁 `http://127.0.0.1:9501/`,對於本章示例引導的情況下,也就是上面的例子所對應的訪問地址為 `http://127.0.0.1:9501/index/info?id=1`。
|
||||
|
||||
## 重新加載代碼
|
||||
|
||||
由於 `Hyperf` 是持久化的 `CLI` 應用,也就意味着一旦進程啟動,已解析的 `PHP` 代碼會持久化在進程中,也就意味着啟動服務後您再修改的 `PHP` 代碼不會改變已啟動的服務,如您希望服務重新加載您修改後的代碼,您需要通過在啟動的 `Console` 中鍵入 `CTRL + C` 終止服務,再重新執行啟動命令 `php bin/hyperf.php start` 完成啟動和重新加載。
|
||||
由於 `Hyperf` 是持久化的 `CLI` 應用,也就意味着一旦進程啓動,已解析的 `PHP` 代碼會持久化在進程中,也就意味着啓動服務後您再修改的 `PHP` 代碼不會改變已啓動的服務,如您希望服務重新加載您修改後的代碼,您需要通過在啓動的 `Console` 中鍵入 `CTRL + C` 終止服務,再重新執行啓動命令 `php bin/hyperf.php start` 完成啓動和重新加載。
|
||||
|
||||
> Tips: 您也可以將啟動 Server 的命令配置在 IDE 上,便可直接通過 IDE 的 `啟動/停止` 操作快捷的完成 `啟動服務` 或 `重啟服務` 的操作。
|
||||
> 且非視圖開發時可以採用 [TDD(Test-Driven Development)](https://baike.baidu.com/item/TDD/9064369) 測試驅動開發來進行開發,這樣不僅可以省略掉服務重啟和頻繁切換窗口的麻煩,還可保證接口數據的正確性。
|
||||
> Tips: 您也可以將啓動 Server 的命令配置在 IDE 上,便可直接通過 IDE 的 `啓動/停止` 操作快捷的完成 `啓動服務` 或 `重啓服務` 的操作。
|
||||
> 且非視圖開發時可以採用 [TDD(Test-Driven Development)](https://baike.baidu.com/item/TDD/9064369) 測試驅動開發來進行開發,這樣不僅可以省略掉服務重啓和頻繁切換窗口的麻煩,還可保證接口數據的正確性。
|
||||
|
||||
> 另外,在文檔 [協程組件庫](zh-hk/awesome-components?id=%e7%83%ad%e6%9b%b4%e6%96%b0%e7%83%ad%e9%87%8d%e8%bd%bd) 一章中提供了多種由社區開發者支持的 熱更新/熱重載 的解決方案,如仍希望採用 熱更新/熱重載 方案可再深入瞭解。
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
> 注意該配置必須於 php.ini 內配置,無法通過 ini_set() 函數來重寫
|
||||
|
||||
當然,也可以通過以下的命令來啟動服務,在執行 PHP 命令時關閉掉 Swoole 短名功能
|
||||
當然,也可以通過以下的命令來啓動服務,在執行 PHP 命令時關閉掉 Swoole 短名功能
|
||||
|
||||
```
|
||||
php -d swoole.use_shortname=Off bin/hyperf.php start
|
||||
@ -46,13 +46,13 @@ php -d swoole.use_shortname=Off bin/hyperf.php start
|
||||
composer dump-autoload -o
|
||||
```
|
||||
|
||||
開發階段,請不要設置 `scan_cacheable` 為 `true`,它會導致 `收集器緩存` 存在時,不會再次掃描文件。另外,官方骨架包中的 `Dockerfile` 是默認開啟這個配置的,`Docker` 環境下開發的同學,請注意這裏。
|
||||
開發階段,請不要設置 `scan_cacheable` 為 `true`,它會導致 `收集器緩存` 存在時,不會再次掃描文件。另外,官方骨架包中的 `Dockerfile` 是默認開啓這個配置的,`Docker` 環境下開發的同學,請注意這裏。
|
||||
|
||||
> 當環境變量存在 SCAN_CACHEABLE 時,.env 中無法修改這個配置。
|
||||
|
||||
## 語法錯誤導致服務無法啟動
|
||||
## 語法錯誤導致服務無法啓動
|
||||
|
||||
當項目啟動時,拋出類似於以下錯誤時
|
||||
當項目啓動時,拋出類似於以下錯誤時
|
||||
|
||||
```
|
||||
Fatal error: Uncaught PhpParser\Error: Syntax error, unexpected T_STRING on line 27 in vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php:315
|
||||
@ -81,13 +81,13 @@ memory_limit=-1
|
||||
|
||||
在 `2.0` - `2.1` 版本時,為了實現 `AOP` 作用於非 `DI` 管理的對象(如 `new` 關鍵詞實例化的對象時),底層實現採用了 `BetterReflection` 組件來實現相關功能,帶來新的編程體驗的同時,也帶來了一些很難攻克的問題,如下:
|
||||
|
||||
- 無掃描緩存時項目啟動很慢
|
||||
- 無掃描緩存時項目啓動很慢
|
||||
- 特殊場景下 `Inject` 和 `Value` 不生效
|
||||
- `BetterReflection` 尚未支持 PHP 8 (截止 2.2 發版時)
|
||||
|
||||
在新的版本里,棄用了 `BetterReflection` 的應用,採用了 `子進程掃描` 的方式來解決以上這些痛點,但在低版本的 `PHP` 中也有一些不兼容的情況:
|
||||
|
||||
使用 `PHP 7.3` 啟動應用後遇到類似如下錯誤:
|
||||
使用 `PHP 7.3` 啓動應用後遇到類似如下錯誤:
|
||||
|
||||
```bash
|
||||
PHP Fatal error: Interface 'Hyperf\Signal\SignalHandlerInterface' not found in vendor/hyperf/process/src/Handler/ProcessStopHandler.php on line 17
|
||||
@ -143,7 +143,7 @@ class IndexController
|
||||
- 子類通過 `as` 修改別名: `use Psr\Http\Message\ResponseInterface as PsrResponseInterface;`
|
||||
- Trait 類`PHP7.4` 以上通過屬性類型限制: `protected ResponseInterface $response;`
|
||||
|
||||
## Grpc 擴展或未安裝 Pcntl 導致項目無法啟動
|
||||
## Grpc 擴展或未安裝 Pcntl 導致項目無法啓動
|
||||
|
||||
- v2.2 版本的註解掃描使用了 `pcntl` 擴展,所以請先確保您的 `PHP` 安裝了此擴展。
|
||||
|
||||
@ -155,9 +155,9 @@ pcntl
|
||||
pcntl support => enabled
|
||||
```
|
||||
|
||||
- 當開啟 `grpc` 的時候,需要添加 `grpc.enable_fork_support= 1;` 到 `php.ini` 中,以支持開啟子進程。
|
||||
- 當開啓 `grpc` 的時候,需要添加 `grpc.enable_fork_support= 1;` 到 `php.ini` 中,以支持開啓子進程。
|
||||
|
||||
## HTTP Server 將 `open_websocket_protocol` 設置為 `false` 後啟動報錯:`Swoole\Server::start(): require onReceive callback`
|
||||
## HTTP Server 將 `open_websocket_protocol` 設置為 `false` 後啓動報錯:`Swoole\Server::start(): require onReceive callback`
|
||||
|
||||
1. 檢查 Swoole 是否編譯了 http2
|
||||
|
||||
|
@ -195,7 +195,7 @@ echo $result->pop(); // 2;
|
||||
|
||||
所有的 HTTP 請求其實也是事件驅動的。所以 HTTP 請求路由也可以用 ReactiveX 來接管。
|
||||
|
||||
> 由於我們要添加路由,所以務必要在 Server 啟動前執行,如在 `BootApplication` 事件監聽中。
|
||||
> 由於我們要添加路由,所以務必要在 Server 啓動前執行,如在 `BootApplication` 事件監聽中。
|
||||
|
||||
假設我們有一個上傳路由,流量很大,需要在內存中緩衝,上傳十次以後再批量入庫。
|
||||
|
||||
@ -328,7 +328,7 @@ $bus->subscribe(function($message){
|
||||
});
|
||||
```
|
||||
|
||||
> 由於 ReactiveX 需要使用事件循環,請注意一定要在 Swoole Server 啟動之後再調用 ReactiveX 相關 API 。
|
||||
> 由於 ReactiveX 需要使用事件循環,請注意一定要在 Swoole Server 啓動之後再調用 ReactiveX 相關 API 。
|
||||
|
||||
## 參考資料
|
||||
|
||||
|
@ -151,7 +151,7 @@ $result = $redis->keys('*');
|
||||
|
||||
## 哨兵模式
|
||||
|
||||
開啟哨兵模式可以在`.env`或 `redis.php` 配置文件中修改如下
|
||||
開啓哨兵模式可以在`.env`或 `redis.php` 配置文件中修改如下
|
||||
|
||||
多個哨兵節點使用`;`分割
|
||||
|
||||
|
@ -164,7 +164,7 @@ class UserController
|
||||
`prefix` 表示該 `Controller` 下的所有方法路由的前綴,默認為類名的小寫,如 `UserController` 則 `prefix` 默認為 `user`,如類內某一方法的 `path` 為 `index`,則最終路由為 `/user/index`。
|
||||
需要注意的是 `prefix` 並非一直有效,當類內的方法的 `path` 以 `/` 開頭時,則表明路徑從 `URI` 頭部開始定義,也就意味着會忽略 `prefix` 的值,同時如果沒有設置 `prefix` 屬性,那麼控制器類命名空間中 `\\Controller\\` 之後的部分會以蛇形命名法(SnakeCase)被用作路由的前綴。
|
||||
|
||||
`server` 表示該路由是定義在哪個 `Server` 之上的,由於 `Hyperf` 支持同時啟動多個 `Server`,也就意味着有可能會同時存在多個 `HTTP Server`,則在定義路由是可以通過 `server` 參數來進行區分這個路由是為了哪個 `Server` 定義的,默認為 `http`。
|
||||
`server` 表示該路由是定義在哪個 `Server` 之上的,由於 `Hyperf` 支持同時啓動多個 `Server`,也就意味着有可能會同時存在多個 `HTTP Server`,則在定義路由是可以通過 `server` 參數來進行區分這個路由是為了哪個 `Server` 定義的,默認為 `http`。
|
||||
|
||||
### 路由參數
|
||||
|
||||
|
@ -102,7 +102,7 @@ return [
|
||||
'retry_interval' => 100,
|
||||
// 多路複用客户端數量
|
||||
'client_count' => 4,
|
||||
// 心跳間隔 非 numeric 表示不開啟心跳
|
||||
// 心跳間隔 非 numeric 表示不開啓心跳
|
||||
'heartbeat' => 30,
|
||||
],
|
||||
],
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
[EasyWeChat](https://www.easywechat.com/) 是一個開源的微信 SDK (非微信官方 SDK)。
|
||||
|
||||
> 如果您使用了 Swoole 4.7.0 及以上版本,並且開啟了 native curl 選項,則可以不按照此文檔進行操作。
|
||||
> 如果您使用了 Swoole 4.7.0 及以上版本,並且開啓了 native curl 選項,則可以不按照此文檔進行操作。
|
||||
|
||||
> 因為組件默認使用 `Curl`,所以我們需要修改對應的 `GuzzleClient` 為協程客户端,或者修改常量 [SWOOLE_HOOK_FLAGS](/zh-hk/coroutine?id=swoole-runtime-hook-level)
|
||||
|
||||
|
@ -33,9 +33,9 @@ composer require hyperf/service-governance-nacos
|
||||
```php
|
||||
return [
|
||||
'enable' => [
|
||||
// 開啟服務發現
|
||||
// 開啓服務發現
|
||||
'discovery' => true,
|
||||
// 開啟服務註冊
|
||||
// 開啓服務註冊
|
||||
'register' => true,
|
||||
],
|
||||
// 服務消費者相關配置
|
||||
|
@ -1,6 +1,6 @@
|
||||
# 信號處理器
|
||||
|
||||
信號處理器會監聽 `Worker` 進程和 `自定義` 進程啟動後,自動註冊到信號管理器中。
|
||||
信號處理器會監聽 `Worker` 進程和 `自定義` 進程啓動後,自動註冊到信號管理器中。
|
||||
|
||||
## 安裝
|
||||
|
||||
@ -112,7 +112,7 @@ class CoroutineServerStopHandler implements SignalHandlerInterface
|
||||
ProcessManager::setRunning(false);
|
||||
|
||||
foreach (ServerManager::list() as [$type, $server]) {
|
||||
// 循環關閉開啟的服務
|
||||
// 循環關閉開啓的服務
|
||||
$server->shutdown();
|
||||
}
|
||||
}
|
||||
|
@ -218,7 +218,7 @@ SocketIORouter::addNamespace('/xxx' , WebSocketController::class);
|
||||
|
||||
在路由中添加。
|
||||
|
||||
### 開啟 Session
|
||||
### 開啓 Session
|
||||
|
||||
安裝並配置好 hyperf/session 組件及其對應中間件,再通過 `SessionAspect` 切入 SocketIO 來使用 Session 。
|
||||
|
||||
|
@ -14,7 +14,7 @@ Swoole Tracker 能夠幫助企業自動分析並彙總統計關鍵系統調用
|
||||
> 各種維度統計服務上報的調用信息, 比如總流量、平均耗時、超時率等,並全面分析報告服務狀況
|
||||
|
||||
- 擁有強大的調試工具鏈
|
||||
> 本系統支持遠程調試,可在系統後台遠程開啟檢測內存泄漏、阻塞檢測、代碼性能分析和查看調用棧;也支持手動埋點進行調試,後台統一查看結果
|
||||
> 本系統支持遠程調試,可在系統後台遠程開啓檢測內存泄漏、阻塞檢測、代碼性能分析和查看調用棧;也支持手動埋點進行調試,後台統一查看結果
|
||||
|
||||
- 同時支持 FPM 和 Swoole
|
||||
> 完美支持 PHP-FPM 環境,不僅限於在 Swoole 中使用
|
||||
@ -58,7 +58,7 @@ extension=/opt/.build/swoole_tracker.so
|
||||
apm.enable=1
|
||||
;採樣率 例如:100%
|
||||
apm.sampling_rate=100
|
||||
;開啟內存泄漏檢測時添加 默認0 關閉狀態
|
||||
;開啓內存泄漏檢測時添加 默認0 關閉狀態
|
||||
apm.enable_memcheck=1
|
||||
|
||||
;Tracker從v3.3.0版本開始修改為了Zend擴展
|
||||
@ -193,7 +193,7 @@ Swoole Tracker 本是一款商業產品,擁有進行內存泄漏檢測的能
|
||||
apm.enable_malloc_hook=1
|
||||
```
|
||||
|
||||
!> 注意:不要在 composer 安裝依賴時開啟;不要在生成代理類緩存時開啟。
|
||||
!> 注意:不要在 composer 安裝依賴時開啓;不要在生成代理類緩存時開啓。
|
||||
|
||||
3. 根據自己的業務,在 Swoole 的 onReceive 或者 onRequest 事件開頭加上 `trackerHookMalloc()` 調用:
|
||||
|
||||
|
@ -191,5 +191,5 @@ $result = $client->query('hyperf.test', [], [
|
||||
|
||||
## 其他方案
|
||||
|
||||
如果 Task 機制無法滿足性能要求,可以嘗試一下 Hyperf 組織下的另一個開源項目[GoTask](https://github.com/hyperf/gotask)。GoTask 通過 Swoole 進程管理功能啟動 Go 進程作為 Swoole 主進程邊車(Sidecar),利用進程通訊將任務投遞給邊車處理並接收返回值。可以理解為 Go 版的 Swoole TaskWorker。
|
||||
如果 Task 機制無法滿足性能要求,可以嘗試一下 Hyperf 組織下的另一個開源項目[GoTask](https://github.com/hyperf/gotask)。GoTask 通過 Swoole 進程管理功能啓動 Go 進程作為 Swoole 主進程邊車(Sidecar),利用進程通訊將任務投遞給邊車處理並接收返回值。可以理解為 Go 版的 Swoole TaskWorker。
|
||||
|
||||
|
@ -47,7 +47,7 @@ composer test
|
||||
|
||||
## 模擬 HTTP 請求
|
||||
|
||||
在開發接口時,我們通常需要一段自動化測試腳本來保證我們提供的接口按預期在運行,Hyperf 框架下提供了 `Hyperf\Testing\Client` 類,可以讓您在不啟動 Server 的情況下,模擬 HTTP 服務的請求:
|
||||
在開發接口時,我們通常需要一段自動化測試腳本來保證我們提供的接口按預期在運行,Hyperf 框架下提供了 `Hyperf\Testing\Client` 類,可以讓您在不啓動 Server 的情況下,模擬 HTTP 服務的請求:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -186,7 +186,7 @@ class ExampleTest extends TestCase
|
||||
|
||||
## 調試代碼
|
||||
|
||||
在 FPM 場景下,我們通常改完代碼,然後打開瀏覽器訪問對應接口,所以我們通常會需要兩個函數 `dd` 和 `dump`,但 `Hyperf` 跑在 `CLI` 模式下,就算提供了這兩個函數,也需要在 `CLI` 中重啟 `Server`,然後再到瀏覽器中調用對應接口查看結果。這樣其實並沒有簡化流程,反而更麻煩了。
|
||||
在 FPM 場景下,我們通常改完代碼,然後打開瀏覽器訪問對應接口,所以我們通常會需要兩個函數 `dd` 和 `dump`,但 `Hyperf` 跑在 `CLI` 模式下,就算提供了這兩個函數,也需要在 `CLI` 中重啓 `Server`,然後再到瀏覽器中調用對應接口查看結果。這樣其實並沒有簡化流程,反而更麻煩了。
|
||||
|
||||
接下來,我來介紹如何通過配合 `testing`,來快速調試代碼,順便完成單元測試。
|
||||
|
||||
|
@ -168,7 +168,7 @@ return [
|
||||
|
||||
JsonRPC 的鏈路追蹤並不在統一配置當中,暫時還屬於 `Beta` 版本的功能。
|
||||
|
||||
我們只需要配置 `aspects.php`,加入以下 `Aspect` 即可開啟。
|
||||
我們只需要配置 `aspects.php`,加入以下 `Aspect` 即可開啓。
|
||||
|
||||
> 提示:不要忘了在對端,添加對應的 TraceMiddleware
|
||||
|
||||
@ -182,8 +182,8 @@ return [
|
||||
|
||||
### 配置中間件
|
||||
|
||||
配置完驅動之後,採集信息還需要配置一下中間件才能啟用採集功能。
|
||||
打開 `config/autoload/middlewares.php` 文件,在 `http` 節點啟用中間件。
|
||||
配置完驅動之後,採集信息還需要配置一下中間件才能啓用採集功能。
|
||||
打開 `config/autoload/middlewares.php` 文件,在 `http` 節點啓用中間件。
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
@ -93,7 +93,7 @@ registry.cn-hangzhou.aliyuncs.com/log-service/logtail
|
||||
|
||||
字段索引屬性
|
||||
|
||||
| 字段名稱 | 類型 | 別名 | 中文分詞 | 開啟統計 |
|
||||
| 字段名稱 | 類型 | 別名 | 中文分詞 | 開啓統計 |
|
||||
| :------: | :---: | :-----: | :------: | :------: |
|
||||
| name | text | name | false | true |
|
||||
| level | text | level | false | true |
|
||||
|
@ -23,7 +23,7 @@ usermod -aG docker $USER
|
||||
|
||||
### 配置倉庫鏡像地址
|
||||
|
||||
基於跨國線路訪問速度過慢等問題,我們可以為 Docker 配置倉庫鏡像地址,來改善這些網絡問題,如 [阿里雲(Aliyun) Docker 鏡像加速器](https://help.aliyun.com/document_detail/60750.html),我們可以申請一個 `Docker` 加速器,然後配置到服務器上的 `/etc/docker/daemon.json` 文件,添加以下內容,然後重啟 `Docker`,下面的地址請填寫您自己獲得的加速器地址。
|
||||
基於跨國線路訪問速度過慢等問題,我們可以為 Docker 配置倉庫鏡像地址,來改善這些網絡問題,如 [阿里雲(Aliyun) Docker 鏡像加速器](https://help.aliyun.com/document_detail/60750.html),我們可以申請一個 `Docker` 加速器,然後配置到服務器上的 `/etc/docker/daemon.json` 文件,添加以下內容,然後重啓 `Docker`,下面的地址請填寫您自己獲得的加速器地址。
|
||||
|
||||
```json
|
||||
{"registry-mirrors": ["https://xxxxx.mirror.aliyuncs.com"]}
|
||||
@ -43,7 +43,7 @@ $ vim /etc/ssh/sshd_config
|
||||
# 默認 Port 改為 2222
|
||||
Port 2222
|
||||
|
||||
# 重啟服務
|
||||
# 重啓服務
|
||||
$ systemctl restart sshd.service
|
||||
```
|
||||
|
||||
@ -55,7 +55,7 @@ ssh -p 2222 root@host
|
||||
|
||||
#### 安裝 Gitlab
|
||||
|
||||
我們來通過 Docker 啟動一個 Gitlab 服務,如下:
|
||||
我們來通過 Docker 啓動一個 Gitlab 服務,如下:
|
||||
|
||||
> hostname 一定要加,如果沒有域名可以直接填外網地址
|
||||
|
||||
@ -234,7 +234,7 @@ cd /backup
|
||||
tar xf data.tar -C /
|
||||
```
|
||||
|
||||
最後只需要重啟容器即可
|
||||
最後只需要重啓容器即可
|
||||
|
||||
## 創建一個 Demo 項目
|
||||
|
||||
@ -359,7 +359,7 @@ docker run --rm \
|
||||
kong:latest kong migrations bootstrap
|
||||
```
|
||||
|
||||
啟動
|
||||
啓動
|
||||
|
||||
```
|
||||
docker run -d --name kong \
|
||||
@ -443,7 +443,7 @@ grub2-set-default 0
|
||||
grub2-mkconfig -o /boot/grub2/grub.cfg
|
||||
```
|
||||
|
||||
- 重啟機器
|
||||
- 重啓機器
|
||||
|
||||
```
|
||||
reboot
|
||||
@ -477,7 +477,7 @@ $ git version
|
||||
$ yum install gitlab-runner
|
||||
```
|
||||
|
||||
### Service 重啟後,內網出現偶發的,容器無法觸達的問題,比如多次在其他容器,訪問此服務的接口,會出現 Connection refused
|
||||
### Service 重啓後,內網出現偶發的,容器無法觸達的問題,比如多次在其他容器,訪問此服務的接口,會出現 Connection refused
|
||||
|
||||
這是由於 IP 不夠用導致,可以修改網段,增加可用 IP
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# Supervisor 部署
|
||||
|
||||
[Supervisor](http://www.supervisord.org/) 是 `Linux/Unix` 系統下的一個進程管理工具。可以很方便的監聽、啟動、停止和重啟一個或多個進程。通過 [Supervisor](http://www.supervisord.org/) 管理的進程,當進程意外被 `Kill` 時,[Supervisor](http://www.supervisord.org/) 會自動將它重啟,可以很方便地做到進程自動恢復的目的,而無需自己編寫 `shell` 腳本來管理進程。
|
||||
[Supervisor](http://www.supervisord.org/) 是 `Linux/Unix` 系統下的一個進程管理工具。可以很方便的監聽、啓動、停止和重啓一個或多個進程。通過 [Supervisor](http://www.supervisord.org/) 管理的進程,當進程意外被 `Kill` 時,[Supervisor](http://www.supervisord.org/) 會自動將它重啓,可以很方便地做到進程自動恢復的目的,而無需自己編寫 `shell` 腳本來管理進程。
|
||||
|
||||
## 安裝 Supervisor
|
||||
|
||||
@ -25,15 +25,15 @@ cp /etc/supervisord.conf /etc/supervisord.d/supervisord.conf
|
||||
[program:hyperf]
|
||||
# 設置命令在指定的目錄內執行
|
||||
directory=/var/www/hyperf/
|
||||
# 這裏為您要管理的項目的啟動命令
|
||||
# 這裏為您要管理的項目的啓動命令
|
||||
command=php ./bin/hyperf.php start
|
||||
# 以哪個用户來運行該進程
|
||||
user=root
|
||||
# supervisor 啟動時自動該應用
|
||||
# supervisor 啓動時自動該應用
|
||||
autostart=true
|
||||
# 進程退出後自動重啟進程
|
||||
# 進程退出後自動重啓進程
|
||||
autorestart=true
|
||||
# 進程持續運行多久才認為是啟動成功
|
||||
# 進程持續運行多久才認為是啓動成功
|
||||
startsecs=1
|
||||
# 重試次數
|
||||
startretries=3
|
||||
@ -45,9 +45,9 @@ stdout_logfile=/var/www/hyperf/runtime/stdout.log
|
||||
|
||||
!> 建議同時增大配置文件中的 `minfds` 配置項,默認為 `1024`。同時也應該修改系統的 [unlimit](https://wiki.swoole.com/#/other/sysctl?id=ulimit-%e8%ae%be%e7%bd%ae),防止出現 `Failed to open stream: Too many open files` 的問題。
|
||||
|
||||
## 啟動 Supervisor
|
||||
## 啓動 Supervisor
|
||||
|
||||
運行下面的命令基於配置文件啟動 Supervisor 程序:
|
||||
運行下面的命令基於配置文件啓動 Supervisor 程序:
|
||||
|
||||
```bash
|
||||
supervisord -c /etc/supervisord.d/supervisord.conf
|
||||
@ -56,9 +56,9 @@ supervisord -c /etc/supervisord.d/supervisord.conf
|
||||
## 使用 supervisorctl 管理項目
|
||||
|
||||
```bash
|
||||
# 啟動 hyperf 應用
|
||||
# 啓動 hyperf 應用
|
||||
supervisorctl start hyperf
|
||||
# 重啟 hyperf 應用
|
||||
# 重啓 hyperf 應用
|
||||
supervisorctl restart hyperf
|
||||
# 停止 hyperf 應用
|
||||
supervisorctl stop hyperf
|
||||
@ -66,6 +66,6 @@ supervisorctl stop hyperf
|
||||
supervisorctl status
|
||||
# 重新加載配置文件
|
||||
supervisorctl update
|
||||
# 重新啟動所有程序
|
||||
# 重新啓動所有程序
|
||||
supervisorctl reload
|
||||
```
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
1.1 版將最低的 Swoole 版本要求從 4.3+ 提升到了 4.4+,這兩個版本之間有一些使用上的細節問題,Hyperf 已經在較早的版本便已適配了,對於 Hyperf 的用户而言無需理會這之間的差異,我們提升最低 Swoole 版本要求主要是為了減少我們的歷史負擔,而 Swoole 4.4 作為 Swoole 的 LTS(長期支持版本) 也意味着更加的穩定可靠。
|
||||
|
||||
Hyperf 在啟動時會進行 Swoole 版本檢測,但為了更好的統一各處對 Swoole 版本的依賴約束,我們建議您將 `composer.json` 內對 Swoole 的依賴條件改為 `"ext-swoole": ">=4.4"`。
|
||||
Hyperf 在啓動時會進行 Swoole 版本檢測,但為了更好的統一各處對 Swoole 版本的依賴約束,我們建議您將 `composer.json` 內對 Swoole 的依賴條件改為 `"ext-swoole": ">=4.4"`。
|
||||
|
||||
## 增加 SWOOLE_HOOK_FLAGS 常量
|
||||
|
||||
@ -48,7 +48,7 @@ return [
|
||||
|
||||
由於 1.1 版本調整了 `dependencies.php` 文件的位置和結構,所處我們還需要調整一下 `config/container.php` 文件,以便依賴注入容器能夠正確的運行,與此同時,我們也為 `config/container.php` 提供了更加簡便的寫法,`DefinitionSourceFactory` 將很多默認的行為聚合了起來,您只需將 `config/container.php` 文件的內容更換成下面的內容即可:
|
||||
|
||||
> 默認開啟註解掃描緩存功能,可修改 `DefinitionSourceFactory` 入參的第一個參數來關閉此功能
|
||||
> 默認開啓註解掃描緩存功能,可修改 `DefinitionSourceFactory` 入參的第一個參數來關閉此功能
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
@ -90,7 +90,7 @@ $container->get(Hyperf\Contract\ApplicationInterface::class);
|
||||
|
||||
## 調整 Dockerfile
|
||||
|
||||
在 Docker 鏡像的打包過程中,主動執行 `php bin/hyperf.php` 命令會幫助提前創建所有需要生成的代理類和註解掃描緩存,這樣在生產環境運行啟動時便無需再次的掃描,這樣可以極大的優化生產環境啟動的時間和內存使用量。以下示例不包含未修改的 Dockerfile 代碼。
|
||||
在 Docker 鏡像的打包過程中,主動執行 `php bin/hyperf.php` 命令會幫助提前創建所有需要生成的代理類和註解掃描緩存,這樣在生產環境運行啓動時便無需再次的掃描,這樣可以極大的優化生產環境啓動的時間和內存使用量。以下示例不包含未修改的 Dockerfile 代碼。
|
||||
|
||||
```dockerfile
|
||||
ENV TIMEZONE=${timezone:-"Asia/Shanghai"} \
|
||||
@ -105,7 +105,7 @@ EXPOSE 9501
|
||||
ENTRYPOINT ["php", "/opt/www/bin/hyperf.php", "start"]
|
||||
```
|
||||
|
||||
非 `Docker` 部署的用户,需要注意的是,在重新啟動服務之前,最好先執行一次 `php bin/hyperf.php` 後再重新啟動服務,以減少重新啟動時的耗時。
|
||||
非 `Docker` 部署的用户,需要注意的是,在重新啓動服務之前,最好先執行一次 `php bin/hyperf.php` 後再重新啓動服務,以減少重新啓動時的耗時。
|
||||
|
||||
## 調整 config/config.php 配置文件
|
||||
|
||||
@ -122,7 +122,7 @@ return [
|
||||
];
|
||||
```
|
||||
|
||||
`scan_cacheable` 配置用於控制應用啟動時是否使用註解掃描緩存,以上 `Dockerfile` 和 `config/config.php` 中都有相關的修改。當這個配置的值為 `true` 時,項目啟動時則會認為所有類都已經完成了掃描並正確生成了對應的緩存和代理,則會跳過掃描階段以便優化啟動時間和減少內存開銷。
|
||||
`scan_cacheable` 配置用於控制應用啓動時是否使用註解掃描緩存,以上 `Dockerfile` 和 `config/config.php` 中都有相關的修改。當這個配置的值為 `true` 時,項目啓動時則會認為所有類都已經完成了掃描並正確生成了對應的緩存和代理,則會跳過掃描階段以便優化啓動時間和減少內存開銷。
|
||||
|
||||
## 修改 `config/autoload/logger.php`
|
||||
|
||||
@ -213,7 +213,7 @@ return [
|
||||
|
||||
## 檢查自定義註解的收集器
|
||||
|
||||
如果您使用了自定義註解且使用了自定義收集器 `Collector` 來收集註解元數據,則需要將對應的 `Collector` 配置到 `annotations.scan.collectors` 中,因為開發模式下,會根據文件的修改時間判斷文件是否修改,然後決定是否重新收集對應的註解元數據。所以,當沒有配置 `annotations.scan.collectors` 時,就會導致註解只在首次啟動 `server` 時可以生效。
|
||||
如果您使用了自定義註解且使用了自定義收集器 `Collector` 來收集註解元數據,則需要將對應的 `Collector` 配置到 `annotations.scan.collectors` 中,因為開發模式下,會根據文件的修改時間判斷文件是否修改,然後決定是否重新收集對應的註解元數據。所以,當沒有配置 `annotations.scan.collectors` 時,就會導致註解只在首次啓動 `server` 時可以生效。
|
||||
|
||||
如在應用層,該配置位於 `config/autoload/annotations.php` 文件,如下:
|
||||
|
||||
@ -245,7 +245,7 @@ return [
|
||||
];
|
||||
```
|
||||
|
||||
## 啟動服務並測試訪問接口
|
||||
## 啓動服務並測試訪問接口
|
||||
|
||||
使用 Swoole 4.5 版本和 view 組件如果出現接口 404 的問題,可以嘗試刪除 `config/autoload/server.php` 文件中的 `static_handler_locations` 配置項。
|
||||
|
||||
|
@ -36,7 +36,7 @@ pcntl
|
||||
pcntl support => enabled
|
||||
```
|
||||
|
||||
> 當開啟 `grpc` 的時候,需要添加 `grpc.enable_fork_support= 1;` 到 `php.ini` 中,以支持開啟子進程。
|
||||
> 當開啓 `grpc` 的時候,需要添加 `grpc.enable_fork_support= 1;` 到 `php.ini` 中,以支持開啓子進程。
|
||||
|
||||
## AMQP
|
||||
|
||||
@ -58,7 +58,7 @@ return [
|
||||
'limit' => 1,
|
||||
],
|
||||
'pool' => [
|
||||
// 同時開啟的連接數
|
||||
// 同時開啓的連接數
|
||||
// 因為新版本連接是支持多路複用的,所以可以用極少的連接數達到很高的併發
|
||||
'connections' => 2,
|
||||
],
|
||||
@ -140,13 +140,13 @@ composer require "hyperf/service-governance-nacos:~2.2.0"
|
||||
|
||||
在 `2.0` - `2.1` 版本時,為了實現 `AOP` 作用於非 `DI` 管理的對象(如 `new` 關鍵詞實例化的對象時),底層實現採用了 `BetterReflection` 組件來實現相關功能,帶來新的編程體驗的同時,也帶來了一些很難攻克的問題,如下:
|
||||
|
||||
- 無掃描緩存時項目啟動很慢
|
||||
- 無掃描緩存時項目啓動很慢
|
||||
- 特殊場景下 `Inject` 和 `Value` 不生效
|
||||
- `BetterReflection` 尚未支持 PHP 8 (截止 2.2 發版時)
|
||||
|
||||
在新的版本里,棄用了 `BetterReflection` 的應用,採用了 `子進程掃描` 的方式來解決以上這些痛點,但在低版本的 `PHP` 中也有一些不兼容的情況:
|
||||
|
||||
使用 `PHP 7.3` 啟動應用後遇到類似如下錯誤:
|
||||
使用 `PHP 7.3` 啓動應用後遇到類似如下錯誤:
|
||||
|
||||
```bash
|
||||
PHP Fatal error: Interface 'Hyperf\Signal\SignalHandlerInterface' not found in vendor/hyperf/process/src/Handler/ProcessStopHandler.php on line 17
|
||||
|
@ -66,7 +66,7 @@ class AppendRequestIdProcessor implements ProcessorInterface
|
||||
|
||||
## Command
|
||||
|
||||
`3.0` 版本後,命令行默認開啟了事件監聽器,所以當有監聽器監聽了 `Command` 的事件,且進行了 `AMQP` 或者其他多路複用的邏輯後,會導致進程無法退出。
|
||||
`3.0` 版本後,命令行默認開啓了事件監聽器,所以當有監聽器監聽了 `Command` 的事件,且進行了 `AMQP` 或者其他多路複用的邏輯後,會導致進程無法退出。
|
||||
|
||||
解決辦法
|
||||
|
||||
@ -108,9 +108,9 @@ class ResumeExitCoordinatorListener implements ListenerInterface
|
||||
}
|
||||
```
|
||||
|
||||
## 啟動服務
|
||||
## 啓動服務
|
||||
|
||||
接下來只需要啟動服務,就可以看到不適配的地方,逐一修改即可。
|
||||
接下來只需要啓動服務,就可以看到不適配的地方,逐一修改即可。
|
||||
|
||||
- AMQP Consumer 和 Producer
|
||||
|
||||
|
@ -2,9 +2,9 @@
|
||||
|
||||
自從 `2.0` 版本使用了 `BetterReflection` 來收集掃描目錄內的 `語法樹` 和 `反射數據`,導致掃描速度相較 `1.1` 慢了不少。
|
||||
|
||||
> 首次啟動,因為沒有任何緩存,所以會比較慢,當二次啟動時,會按照文件修改時間,進行動態收集,但因為仍需要實例化 `BetterReflection`,所以啟動時間仍然比較長。
|
||||
> 首次啓動,因為沒有任何緩存,所以會比較慢,當二次啓動時,會按照文件修改時間,進行動態收集,但因為仍需要實例化 `BetterReflection`,所以啓動時間仍然比較長。
|
||||
|
||||
`Watcher` 組件除了解決上述啟動問題,還提供了文件修改後立馬重啟的功能。
|
||||
`Watcher` 組件除了解決上述啓動問題,還提供了文件修改後立馬重啓的功能。
|
||||
|
||||
## 安裝
|
||||
|
||||
@ -25,7 +25,7 @@ php bin/hyperf.php vendor:publish hyperf/watcher
|
||||
| 配置 | 默認值 | 備註 |
|
||||
| :------------: | :--------------: | :-------------------------------------------------------: |
|
||||
| driver | `ScanFileDriver` | 默認定時掃描文件驅動 |
|
||||
| bin | `php` | 用於啟動服務的腳本 例如 `php -d swoole.use_shortname=Off` |
|
||||
| bin | `php` | 用於啓動服務的腳本 例如 `php -d swoole.use_shortname=Off` |
|
||||
| watch.dir | `app`, `config` | 監聽目錄 |
|
||||
| watch.file | `.env` | 監聽文件 |
|
||||
| watch.interval | `2000` | 掃描間隔(毫秒) |
|
||||
@ -64,7 +64,7 @@ wget https://github.com/emcrisostomo/fswatch/releases/download/1.14.0/fswatch-1.
|
||||
&& make install
|
||||
```
|
||||
|
||||
## 啟動
|
||||
## 啓動
|
||||
|
||||
因為目錄的關係,需要在項目根目錄中運行。
|
||||
|
||||
@ -75,6 +75,6 @@ php bin/hyperf.php server:watch
|
||||
## 不足
|
||||
|
||||
- 暫時 Alpine Docker 環境下,稍微有點問題,後續會完善。
|
||||
- 刪除文件和修改`.env`需要手動重啟才能生效。
|
||||
- 刪除文件和修改`.env`需要手動重啓才能生效。
|
||||
- vendor 中的文件需要使用 classmap 形式自動加載才能被掃描。(即執行`composer dump-autoload -o`)
|
||||
|
||||
|
@ -103,7 +103,7 @@ class WebSocketController implements OnMessageInterface, OnOpenInterface, OnClos
|
||||
}
|
||||
```
|
||||
|
||||
接下來啟動 Server,便能看到對應啟動了一個 WebSocket Server 並監聽於 9502 端口,此時您便可以通過各種 WebSocket Client 來進行連接和數據傳輸了。
|
||||
接下來啓動 Server,便能看到對應啓動了一個 WebSocket Server 並監聽於 9502 端口,此時您便可以通過各種 WebSocket Client 來進行連接和數據傳輸了。
|
||||
|
||||
```
|
||||
$ php bin/hyperf.php start
|
||||
|
@ -14,7 +14,7 @@ Hyperf 還提供了 `基於 PSR-11 的依賴注入容器`、`註解`、`AOP 面
|
||||
|
||||
`Hyperspeed + Flexibility = Hyperf`,從名字上我們就將 `超高速` 和 `靈活性` 作為 Hyperf 的基因。
|
||||
|
||||
- 對於超高速,我們基於 Swoole 協程並在框架設計上進行大量的優化以確保超高效能的輸出。
|
||||
- 對於超高速,我們基於 Swoole 協程並在框架設計上進行大量的最佳化以確保超高效能的輸出。
|
||||
- 對於靈活性,我們基於 Hyperf 強大的依賴注入元件,元件均基於 [PSR 標準](https://www.php-fig.org/psr) 的契約和由 Hyperf 定義的契約實現,達到框架內的絕大部分的元件或類都是可替換的。
|
||||
|
||||
基於以上的特點,Hyperf 將存在豐富的可能性,如實現 Web 服務,閘道器服務,分散式中介軟體,微服務架構,遊戲伺服器,物聯網(IOT)等。
|
||||
|
@ -102,7 +102,7 @@ class DemoProducer extends ProducerMessage
|
||||
|
||||
```
|
||||
|
||||
通過 DI Container 獲取 `Hyperf\Amqp\Producer` 例項,即可投遞訊息。以下例項直接使用 `ApplicationContext` 獲取 `Hyperf\Amqp\Producer` 其實並不合理,DI Container 具體使用請到 [依賴注入](zh-tw/di.md) 章節中檢視。
|
||||
透過 DI Container 獲取 `Hyperf\Amqp\Producer` 例項,即可投遞訊息。以下例項直接使用 `ApplicationContext` 獲取 `Hyperf\Amqp\Producer` 其實並不合理,DI Container 具體使用請到 [依賴注入](zh-tw/di.md) 章節中檢視。
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -364,11 +364,11 @@ php bin/hyperf.php demo:command
|
||||
|
||||
## RPC 遠端過程呼叫
|
||||
|
||||
除了典型的訊息佇列場景,我們還可以通過 AMQP 來實現 RPC 遠端過程呼叫,本元件也為這個實現提供了對應的支援。
|
||||
除了典型的訊息佇列場景,我們還可以透過 AMQP 來實現 RPC 遠端過程呼叫,本元件也為這個實現提供了對應的支援。
|
||||
|
||||
### 建立消費者
|
||||
|
||||
RPC 使用的消費者,與典型訊息佇列場景的消費者實現基本無差,唯一的區別是需要通過呼叫 `reply` 方法返回資料給生產者。
|
||||
RPC 使用的消費者,與典型訊息佇列場景的消費者實現基本無差,唯一的區別是需要透過呼叫 `reply` 方法返回資料給生產者。
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -398,7 +398,7 @@ class ReplyConsumer extends ConsumerMessage
|
||||
|
||||
### 發起 RPC 呼叫
|
||||
|
||||
作為生成者發起一次 RPC 遠端過程呼叫也非常的簡單,只需通過依賴注入容器獲得 `Hyperf\Amqp\RpcClient` 物件並呼叫其中的 `call` 方法即可,返回的結果是消費者 reply 的資料,如下所示:
|
||||
作為生成者發起一次 RPC 遠端過程呼叫也非常的簡單,只需透過依賴注入容器獲得 `Hyperf\Amqp\RpcClient` 物件並呼叫其中的 `call` 方法即可,返回的結果是消費者 reply 的資料,如下所示:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -419,7 +419,7 @@ $result = $rpcClient->call(new DynamicRpcMessage('hyperf', 'hyperf', ['message'
|
||||
|
||||
### 抽象 RpcMessage
|
||||
|
||||
上面的 RPC 呼叫過程是直接通過 `Hyperf\Amqp\Message\DynamicRpcMessage` 類來完成 Exchange 和 RoutingKey 的定義,並傳遞訊息資料,在生產專案的設計上,我們可以對 RpcMessage 進行一層抽象,以統一 Exchange 和 RoutingKey 的定義。
|
||||
上面的 RPC 呼叫過程是直接透過 `Hyperf\Amqp\Message\DynamicRpcMessage` 類來完成 Exchange 和 RoutingKey 的定義,並傳遞訊息資料,在生產專案的設計上,我們可以對 RpcMessage 進行一層抽象,以統一 Exchange 和 RoutingKey 的定義。
|
||||
|
||||
我們可以建立對應的 RpcMessage 類如 `App\Amqp\FooRpcMessage` 如下:
|
||||
|
||||
|
@ -1,14 +1,14 @@
|
||||
# 註解
|
||||
|
||||
註解是 Hyperf 非常強大的一項功能,可以通過註解的形式減少很多的配置,以及實現很多非常方便的功能。
|
||||
註解是 Hyperf 非常強大的一項功能,可以透過註解的形式減少很多的配置,以及實現很多非常方便的功能。
|
||||
|
||||
## 概念
|
||||
|
||||
### 什麼是註解?
|
||||
|
||||
註解功能提供了程式碼中的宣告部分都可以新增結構化、機器可讀的元資料的能力, 註解的目標可以是類、方法、函式、引數、屬性、類常量。 通過 反射 API 可在執行時獲取註解所定義的元資料。 因此註解可以成為直接嵌入程式碼的配置式語言。
|
||||
註解功能提供了程式碼中的宣告部分都可以新增結構化、機器可讀的元資料的能力, 註解的目標可以是類、方法、函式、引數、屬性、類常量。 透過 反射 API 可在執行時獲取註解所定義的元資料。 因此註解可以成為直接嵌入程式碼的配置式語言。
|
||||
|
||||
通過註解的使用,在應用中實現功能、使用功能可以相互解耦。 某種程度上講,它可以和介面(interface)與其實現(implementation)相比較。 但介面與實現是程式碼相關的,註解則與宣告額外資訊和配置相關。 介面可以通過類來實現,而註解也可以宣告到方法、函式、引數、屬性、類常量中。 因此它們比介面更靈活。
|
||||
透過註解的使用,在應用中實現功能、使用功能可以相互解耦。 某種程度上講,它可以和介面(interface)與其實現(implementation)相比較。 但介面與實現是程式碼相關的,註解則與宣告額外資訊和配置相關。 介面可以透過類來實現,而註解也可以宣告到方法、函式、引數、屬性、類常量中。 因此它們比介面更靈活。
|
||||
|
||||
註解使用的一個簡單例子:將介面(interface)的可選方法改用註解實現。 我們假設介面 ActionHandler 代表了應用的一個操作: 部分 action handler 的實現需要 setup,部分不需要。 我們可以使用註解,而不用要求所有類必須實現 ActionHandler 介面並實現 setUp() 方法。 因此帶來一個好處——可以多次使用註解。
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
|
||||
### 忽略某些註解
|
||||
|
||||
在一些情況下我們可能希望忽略某些 註解,比如我們在接入一些自動生成文件的工具時,有不少工具都是通過註解的形式去定義文件的相關結構內容的,而這些註解可能並不符合 Hyperf 的使用方式,我們可以通過在 `config/autoload/annotations.php` 內將相關注解設定為忽略。
|
||||
在一些情況下我們可能希望忽略某些 註解,比如我們在接入一些自動生成文件的工具時,有不少工具都是透過註解的形式去定義文件的相關結構內容的,而這些註解可能並不符合 Hyperf 的使用方式,我們可以透過在 `config/autoload/annotations.php` 內將相關注解設定為忽略。
|
||||
|
||||
```php
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
@ -138,7 +138,7 @@ return [
|
||||
|
||||
### 利用註解資料
|
||||
|
||||
在沒有自定義註解收集方法時,預設會將註解的元資料統一收集在 `Hyperf\Di\Annotation\AnnotationCollector` 類內,通過該類的靜態方法可以方便的獲取對應的元資料用於邏輯判斷或實現。
|
||||
在沒有自定義註解收集方法時,預設會將註解的元資料統一收集在 `Hyperf\Di\Annotation\AnnotationCollector` 類內,透過該類的靜態方法可以方便的獲取對應的元資料用於邏輯判斷或實現。
|
||||
|
||||
### ClassMap 功能
|
||||
|
||||
|
@ -2,9 +2,9 @@
|
||||
|
||||
## 概念
|
||||
|
||||
AOP 為 `Aspect Oriented Programming` 的縮寫,意為:`面向切面程式設計`,通過動態代理等技術實現程式功能的統一維護的一種技術。AOP 是 OOP 的延續,也是 Hyperf 中的一個重要內容,是函數語言程式設計的一種衍生範型。利用 AOP 可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率。
|
||||
AOP 為 `Aspect Oriented Programming` 的縮寫,意為:`面向切面程式設計`,透過動態代理等技術實現程式功能的統一維護的一種技術。AOP 是 OOP 的延續,也是 Hyperf 中的一個重要內容,是函數語言程式設計的一種衍生範型。利用 AOP 可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率。
|
||||
|
||||
用通俗的話來講,就是在 Hyperf 裡可以通過 `切面(Aspect)` 介入到任意類的任意方法的執行流程中去,從而改變或加強原方法的功能,這就是 AOP。
|
||||
用通俗的話來講,就是在 Hyperf 裡可以透過 `切面(Aspect)` 介入到任意類的任意方法的執行流程中去,從而改變或加強原方法的功能,這就是 AOP。
|
||||
|
||||
> 注意這裡所指的任意類並不是完全意義上的所有類,在 Hyperf 啟動初期用於實現 AOP 功能的類自身不能被切入。
|
||||
|
||||
@ -17,7 +17,7 @@ AOP 為 `Aspect Oriented Programming` 的縮寫,意為:`面向切面程式
|
||||
|
||||
## 定義切面(Aspect)
|
||||
|
||||
每個 `切面(Aspect)` 必須實現 `Hyperf\Di\Aop\AroundInterface` 介面,並提供 `public` 的 `$classes` 和 `$annotations` 屬性,為了方便使用,我們可以通過繼承 `Hyperf\Di\Aop\AbstractAspect` 來簡化定義過程,我們通過程式碼來描述一下。
|
||||
每個 `切面(Aspect)` 必須實現 `Hyperf\Di\Aop\AroundInterface` 介面,並提供 `public` 的 `$classes` 和 `$annotations` 屬性,為了方便使用,我們可以透過繼承 `Hyperf\Di\Aop\AbstractAspect` 來簡化定義過程,我們透過程式碼來描述一下。
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -32,7 +32,7 @@ use Hyperf\Di\Aop\ProceedingJoinPoint;
|
||||
#[Aspect]
|
||||
class FooAspect extends AbstractAspect
|
||||
{
|
||||
// 要切入的類或 Trait,可以多個,亦可通過 :: 標識到具體的某個方法,通過 * 可以模糊匹配
|
||||
// 要切入的類或 Trait,可以多個,亦可透過 :: 標識到具體的某個方法,透過 * 可以模糊匹配
|
||||
public array $classes = [
|
||||
SomeClass::class,
|
||||
'App\Service\SomeClass::someMethod',
|
||||
@ -47,7 +47,7 @@ class FooAspect extends AbstractAspect
|
||||
public function process(ProceedingJoinPoint $proceedingJoinPoint)
|
||||
{
|
||||
// 切面切入後,執行對應的方法會由此來負責
|
||||
// $proceedingJoinPoint 為連線點,通過該類的 process() 方法呼叫原方法並獲得結果
|
||||
// $proceedingJoinPoint 為連線點,透過該類的 process() 方法呼叫原方法並獲得結果
|
||||
// 在呼叫前進行某些處理
|
||||
$result = $proceedingJoinPoint->process();
|
||||
// 在呼叫後進行某些處理
|
||||
@ -60,7 +60,7 @@ class FooAspect extends AbstractAspect
|
||||
|
||||
> 使用 `@Aspect` 註解時需 `use Hyperf\Di\Annotation\Aspect;` 名稱空間;
|
||||
|
||||
您也可以通過 `@Aspect` 註解本身的屬性來完成切入目標的配置,通過下面註解的形式可以達到與上面的示例一樣的目的:
|
||||
您也可以透過 `@Aspect` 註解本身的屬性來完成切入目標的配置,透過下面註解的形式可以達到與上面的示例一樣的目的:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -89,7 +89,7 @@ class FooAspect extends AbstractAspect
|
||||
public function process(ProceedingJoinPoint $proceedingJoinPoint)
|
||||
{
|
||||
// 切面切入後,執行對應的方法會由此來負責
|
||||
// $proceedingJoinPoint 為連線點,通過該類的 process() 方法呼叫原方法並獲得結果
|
||||
// $proceedingJoinPoint 為連線點,透過該類的 process() 方法呼叫原方法並獲得結果
|
||||
// 在呼叫前進行某些處理
|
||||
$result = $proceedingJoinPoint->process();
|
||||
// 在呼叫後進行某些處理
|
||||
@ -102,6 +102,6 @@ class FooAspect extends AbstractAspect
|
||||
|
||||
所有被 AOP 影響的類,都會在 `./runtime/container/proxy/` 資料夾內生成對應的 `代理類快取`,是否在啟動時自動生成取決於 `config/config.php` 配置檔案中 `scan_cacheable` 配置項的值,預設值為 `false`,如果該配置項為 `true` 則 Hyperf 不會掃描和生成代理類快取,而是直接以現有的快取檔案作為最終的代理類。如果該配置項為 `false`,則 Hyperf 會在每次啟動應用時掃描註解掃描域並自動的生成對應的代理類快取,當代碼發生變化時,代理類快取也會自動的重新生成。
|
||||
|
||||
通常在開發環境下,該值為 `false`,這樣更便於開發除錯,而在部署生產環境時,我們可能會希望 Hyperf 提前將所有代理類提前生成,而不是使用時動態的生成,可以通過 `php bin/hyperf.php` 命令來生成所有代理類,然後再通過環境變數 `SCAN_CACHEABLE` 為 `true` 修改該配置項的值,以達到啟動時間更短、應用記憶體佔用更低的目的。
|
||||
通常在開發環境下,該值為 `false`,這樣更便於開發除錯,而在部署生產環境時,我們可能會希望 Hyperf 提前將所有代理類提前生成,而不是使用時動態的生成,可以透過 `php bin/hyperf.php` 命令來生成所有代理類,然後再透過環境變數 `SCAN_CACHEABLE` 為 `true` 修改該配置項的值,以達到啟動時間更短、應用記憶體佔用更低的目的。
|
||||
|
||||
基於以上,如果您使用 Docker 或 Kubernetes 等虛擬化技術來部署您的應用的話,您可以在映象構建階段就生成對應的代理類快取並寫入到映象中去,在執行映象例項時,可大大減少啟動時間和應用記憶體。
|
||||
|
@ -186,7 +186,7 @@ class ExampleJob extends Job
|
||||
public function handle()
|
||||
{
|
||||
// 根據引數處理具體邏輯
|
||||
// 通過具體引數獲取模型等
|
||||
// 透過具體引數獲取模型等
|
||||
// 這裡的邏輯會在 ConsumerProcess 程序中執行
|
||||
var_dump($this->params);
|
||||
}
|
||||
|
@ -122,13 +122,13 @@
|
||||
|
||||
- [hyperf/swoole-tracker](https://github.com/hyperf/swoole-tracker) Hyperf 官方提供的對接 Swoole Tracker 的元件,提供阻塞分析、效能分析、記憶體洩漏分析、執行狀態及呼叫統計等功能
|
||||
- [hyperf/task](https://github.com/hyperf/task) Hyperf 官方提供的 Task 元件,對 Swoole 的 Task 機制進行了封裝及抽象,提供便捷的註解用法
|
||||
- [hyperf/gotask](https://github.com/hyperf/gotask) GoTask 通過 Swoole 程序管理功能啟動 Go 程序作為 Swoole 主程序邊車(Sidecar),利用程序通訊將任務投遞給邊車處理並接收返回值。可以理解為 Go 版的 Swoole TaskWorker。
|
||||
- [hyperf/gotask](https://github.com/hyperf/gotask) GoTask 透過 Swoole 程序管理功能啟動 Go 程序作為 Swoole 主程序邊車(Sidecar),利用程序通訊將任務投遞給邊車處理並接收返回值。可以理解為 Go 版的 Swoole TaskWorker。
|
||||
|
||||
## 開發除錯
|
||||
|
||||
- [swoole/yasd](https://github.com/swoole/yasd) Swoole 偵錯程式,類似 `Xdebug`,完美支援協程,支援斷點除錯、單步追蹤、`watch` 變數
|
||||
- [firstphp/wsdebug](https://github.com/lamplife/wsdebug) 通過 `WebSocket` 實時觀測異常錯誤的開發除錯元件
|
||||
- [qbhy/hyperf-multi-env](https://github.com/qbhy/hyperf-multi-env) 支援與 laravel 類似的多 env 配置檔案功能,比如通過 `APP_ENV=testing` 可以載入 `.env.testing` 配置覆蓋預設的 `.env`
|
||||
- [firstphp/wsdebug](https://github.com/lamplife/wsdebug) 透過 `WebSocket` 實時觀測異常錯誤的開發除錯元件
|
||||
- [qbhy/hyperf-multi-env](https://github.com/qbhy/hyperf-multi-env) 支援與 laravel 類似的多 env 配置檔案功能,比如透過 `APP_ENV=testing` 可以載入 `.env.testing` 配置覆蓋預設的 `.env`
|
||||
- [qiutuleng/hyperf-dump-server](https://github.com/qiutuleng/hyperf-dump-server) 提供一個 `dump` 函式,可以將程式內的變數或資料列印到另一個命令列視窗中,基於 Symfony 的 `Var-Dump Server` 元件
|
||||
- [leearvin/hyperf-tinker](https://github.com/Arvin-Lee/hyperf-tinker) 基於 PsySH 提供一個互動式的 Hyperf shell 容器
|
||||
|
||||
|
@ -44,7 +44,7 @@ $cache = $container->get(\Psr\SimpleCache\CacheInterface::class);
|
||||
元件提供 `Hyperf\Cache\Annotation\Cacheable` 註解,作用於類方法,可以配置對應的快取字首、失效時間、監聽器和快取組。
|
||||
例如,UserService 提供一個 user 方法,可以查詢對應 id 的使用者資訊。當加上 `Hyperf\Cache\Annotation\Cacheable` 註解後,會自動生成對應的 Redis 快取,key 值為 `user:id` ,超時時間為 `9000` 秒。首次查詢時,會從資料庫中查,後面查詢時,會從快取中查。
|
||||
|
||||
> 快取註解基於 [aop](zh-tw/aop.md) 和 [di](zh-tw/di.md),所以只有在 `Container` 中獲取到的物件例項才有效,比如通過 `$container->get` 和 `make` 方法所獲得的物件,直接 `new` 出來的物件無法使用。
|
||||
> 快取註解基於 [aop](zh-tw/aop.md) 和 [di](zh-tw/di.md),所以只有在 `Container` 中獲取到的物件例項才有效,比如透過 `$container->get` 和 `make` 方法所獲得的物件,直接 `new` 出來的物件無法使用。
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -4,7 +4,7 @@ Hyperf 的命令列預設由 [hyperf/command](https://github.com/hyperf/command)
|
||||
|
||||
# 安裝
|
||||
|
||||
通常來說該元件會預設存在,但如果您希望用於非 Hyperf 專案,也可通過下面的命令依賴 [hyperf/command](https://github.com/hyperf/command) 元件:
|
||||
通常來說該元件會預設存在,但如果您希望用於非 Hyperf 專案,也可透過下面的命令依賴 [hyperf/command](https://github.com/hyperf/command) 元件:
|
||||
|
||||
```bash
|
||||
composer require hyperf/command
|
||||
@ -18,7 +18,7 @@ composer require hyperf/command
|
||||
|
||||
## 生成命令
|
||||
|
||||
如果你有安裝 [hyperf/devtool](https://github.com/hyperf/devtool) 元件的話,可以通過 `gen:command` 命令來生成一個自定義命令:
|
||||
如果你有安裝 [hyperf/devtool](https://github.com/hyperf/devtool) 元件的話,可以透過 `gen:command` 命令來生成一個自定義命令:
|
||||
|
||||
```bash
|
||||
php bin/hyperf.php gen:command FooCommand
|
||||
@ -27,7 +27,7 @@ php bin/hyperf.php gen:command FooCommand
|
||||
|
||||
### 定義命令
|
||||
|
||||
定義該命令類所對應的命令有兩種形式,一種是通過 `$name` 屬性定義,另一種是通過建構函式傳參來定義,我們通過程式碼示例來演示一下,假設我們希望定義該命令類的命令為 `foo:hello`:
|
||||
定義該命令類所對應的命令有兩種形式,一種是透過 `$name` 屬性定義,另一種是透過建構函式傳參來定義,我們透過程式碼示例來演示一下,假設我們希望定義該命令類的命令為 `foo:hello`:
|
||||
|
||||
#### `$name` 屬性定義:
|
||||
|
||||
@ -97,7 +97,7 @@ class FooCommand extends HyperfCommand
|
||||
|
||||
public function handle()
|
||||
{
|
||||
// 通過內建方法 line 在 Console 輸出 Hello Hyperf.
|
||||
// 透過內建方法 line 在 Console 輸出 Hello Hyperf.
|
||||
$this->line('Hello Hyperf.', 'info');
|
||||
}
|
||||
}
|
||||
@ -105,11 +105,11 @@ class FooCommand extends HyperfCommand
|
||||
|
||||
### 定義命令類的引數
|
||||
|
||||
在編寫命令時,通常是通過 `引數` 和 `選項` 來收集使用者的輸入的,在收集一個使用者輸入前,必須對該 `引數` 或 `選項` 進行定義。
|
||||
在編寫命令時,通常是透過 `引數` 和 `選項` 來收集使用者的輸入的,在收集一個使用者輸入前,必須對該 `引數` 或 `選項` 進行定義。
|
||||
|
||||
#### 引數
|
||||
|
||||
假設我們希望定義一個 `name` 引數,然後通過傳遞任意字串如 `Hyperf` 於命令一起並執行 `php bin/hyperf.php foo:hello Hyperf` 輸出 `Hello Hyperf`,我們通過程式碼來演示一下:
|
||||
假設我們希望定義一個 `name` 引數,然後透過傳遞任意字串如 `Hyperf` 於命令一起並執行 `php bin/hyperf.php foo:hello Hyperf` 輸出 `Hello Hyperf`,我們透過程式碼來演示一下:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -274,7 +274,7 @@ array(2) {
|
||||
public function configure()
|
||||
{
|
||||
parent::configure();
|
||||
$this->addOption('opt', 'o', InputOption::VALUE_NONE, '是否優化');
|
||||
$this->addOption('opt', 'o', InputOption::VALUE_NONE, '是否最佳化');
|
||||
}
|
||||
|
||||
public function handle()
|
||||
@ -345,7 +345,7 @@ array(2) {
|
||||
|
||||
```
|
||||
|
||||
## 通過 `$signature` 配置命令列
|
||||
## 透過 `$signature` 配置命令列
|
||||
|
||||
命令列除了上述配置方法外,還支援使用 `$signature` 配置。
|
||||
|
||||
@ -403,7 +403,7 @@ class DebugCommand extends HyperfCommand
|
||||
|
||||
# 執行命令
|
||||
|
||||
!> 注意:在執行命令時,預設不會觸發事件分發,可通過新增 `--enable-event-dispatcher` 引數來開啟。
|
||||
!> 注意:在執行命令時,預設會觸發事件分發,可透過新增 `--disable-event-dispatcher` 引數來開啟。
|
||||
|
||||
## 命令列中執行
|
||||
|
||||
|
@ -90,15 +90,15 @@ php bin/hyperf.php vendor:publish hyperf/amqp
|
||||
|
||||
# ConfigProvider 機制的執行流程
|
||||
|
||||
關於 `ConfigProvider` 的配置並非一定就是這樣去劃分,這是一些約定成俗的格式,實際上最終如何來解析這些配置的決定權也在於使用者,使用者可通過修改 Skeleton 專案的 `config/container.php` 檔案內的程式碼來調整相關的載入,也就意味著,`config/container.php` 檔案決定了 `ConfigProvider` 的掃描和載入。
|
||||
關於 `ConfigProvider` 的配置並非一定就是這樣去劃分,這是一些約定成俗的格式,實際上最終如何來解析這些配置的決定權也在於使用者,使用者可透過修改 Skeleton 專案的 `config/container.php` 檔案內的程式碼來調整相關的載入,也就意味著,`config/container.php` 檔案決定了 `ConfigProvider` 的掃描和載入。
|
||||
|
||||
# 元件設計規範
|
||||
|
||||
由於 `composer.json` 內的 `extra` 屬性在資料不被利用時無其它作用和影響,故這些元件內的定義在其它框架使用時,不會造成任何的干擾和影響,故`ConfigProvider` 是一種僅作用於 Hyperf 框架的機制,對其它沒有利用此機制的框架不會造成任何的影響,這也就為元件的複用打下了基礎,但這也要求在進行元件設計時,必須遵循以下規範:
|
||||
|
||||
- 所有類的設計都必須允許通過標準 `OOP` 的使用方式來使用,所有 Hyperf 專有的功能必須作為增強功能並以單獨的類來提供,也就意味著在非 Hyperf 框架下仍能通過標準的手段來實現元件的使用;
|
||||
- 所有類的設計都必須允許透過標準 `OOP` 的使用方式來使用,所有 Hyperf 專有的功能必須作為增強功能並以單獨的類來提供,也就意味著在非 Hyperf 框架下仍能透過標準的手段來實現元件的使用;
|
||||
- 元件的依賴設計如果可滿足 [PSR 標準](https://www.php-fig.org/psr) 則優先滿足且依賴對應的介面而不是實現類;如 [PSR 標準](https://www.php-fig.org/psr) 沒有包含的功能,則可滿足由 Hyperf 定義的契約庫 [Hyperf/contract](https://github.com/hyperf/contract) 內的介面時優先滿足且依賴對應的介面而不是實現類;
|
||||
- 對於實現 Hyperf 專有功能所增加的增強功能類,通常來說也會對 Hyperf 的一些元件有依賴,那麼這些元件的依賴不應該寫在 `composer.json` 的 `require` 項,而是寫在 `suggest` 項作為建議項存在;
|
||||
- 元件設計時不應該通過註解進行任何的依賴注入,注入方式應只使用 `建構函式注入` 的方式,這樣同時也能滿足在 `OOP` 下的使用;
|
||||
- 元件設計時不應該通過註解進行任何的功能定義,功能定義應只通過 `ConfigProvider` 來定義;
|
||||
- 類的設計時應儘可能的不儲存狀態資料,因為這會導致這個類不能作為長生命週期的物件來提供,也無法很方便的使用依賴注入功能,這樣會在一定程度下降低效能,狀態資料應都通過 `Hyperf\Context\Context` 協程上下文來儲存;
|
||||
- 元件設計時不應該透過註解進行任何的依賴注入,注入方式應只使用 `建構函式注入` 的方式,這樣同時也能滿足在 `OOP` 下的使用;
|
||||
- 元件設計時不應該透過註解進行任何的功能定義,功能定義應只通過 `ConfigProvider` 來定義;
|
||||
- 類的設計時應儘可能的不儲存狀態資料,因為這會導致這個類不能作為長生命週期的物件來提供,也無法很方便的使用依賴注入功能,這樣會在一定程度下降低效能,狀態資料應都透過 `Hyperf\Context\Context` 協程上下文來儲存;
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
# 元件開發的目的
|
||||
|
||||
在傳統的 PHP-FPM 架構下的開發,通常在我們需要藉助第三方庫來解決我們的需求時,都會通過 Composer 來直接引入一個對應的 `庫(Library)`,但是在 Hyperf 下,由於 `持久化應用` 和 `協程` 這兩個特性,導致了應用的生命週期和模式存在一些差異,所以並不是所有的 `庫(Library)` 都能在 Hyperf 裡直接使用,當然,一些設計優秀的 `庫(Library)` 也是可以被直接使用的。通讀本指南,便可知道如何甄別一些 `庫(Library)` 是否能直接用於專案內,不能的話該進行如何的改動。
|
||||
在傳統的 PHP-FPM 架構下的開發,通常在我們需要藉助第三方庫來解決我們的需求時,都會透過 Composer 來直接引入一個對應的 `庫(Library)`,但是在 Hyperf 下,由於 `持久化應用` 和 `協程` 這兩個特性,導致了應用的生命週期和模式存在一些差異,所以並不是所有的 `庫(Library)` 都能在 Hyperf 裡直接使用,當然,一些設計優秀的 `庫(Library)` 也是可以被直接使用的。通讀本指南,便可知道如何甄別一些 `庫(Library)` 是否能直接用於專案內,不能的話該進行如何的改動。
|
||||
|
||||
# 元件開發準備工作
|
||||
|
||||
@ -35,7 +35,7 @@ git clone git@github.com:hyperf/hyperf.git
|
||||
└── vendor
|
||||
```
|
||||
|
||||
這樣做的目的是為了讓 `hyperf-skeleton` 專案可以直接通過 `path` 來源的形式,讓 Composer 直接通過 `hyperf` 資料夾內的專案作為依賴項被載入到 `hyperf-skelton` 專案的 `vendor` 目錄中,我們對 `hyperf-skelton` 內的 `composer.json` 檔案增加一個 `repositories` 項,如下:
|
||||
這樣做的目的是為了讓 `hyperf-skeleton` 專案可以直接透過 `path` 來源的形式,讓 Composer 直接透過 `hyperf` 資料夾內的專案作為依賴項被載入到 `hyperf-skelton` 專案的 `vendor` 目錄中,我們對 `hyperf-skelton` 內的 `composer.json` 檔案增加一個 `repositories` 項,如下:
|
||||
|
||||
```json
|
||||
{
|
||||
@ -58,7 +58,7 @@ cd hyperf-skeleton
|
||||
rm -rf composer.lock && rm -rf vendor && composer update
|
||||
```
|
||||
|
||||
最終使 `hyperf-skeleton/vendor/hyperf` 資料夾內的專案資料夾全部通過 `軟連線(softlink)` 連線到 `hyperf` 資料夾內。我們可以通過 `ls -l` 命令來驗證 `軟連線(softlink)` 是否已經建立成功:
|
||||
最終使 `hyperf-skeleton/vendor/hyperf` 資料夾內的專案資料夾全部透過 `軟連線(softlink)` 連線到 `hyperf` 資料夾內。我們可以透過 `ls -l` 命令來驗證 `軟連線(softlink)` 是否已經建立成功:
|
||||
|
||||
```bash
|
||||
cd vendor/hyperf/
|
||||
|
@ -16,7 +16,7 @@ Hyperf 為您提供了分散式系統的外部化配置支援,預設適配了:
|
||||
- 時效性:修改配置,需要每臺伺服器每個應用修改並重啟服務
|
||||
- 侷限性:無法支援動態調整,例如日誌開關、功能開關等
|
||||
|
||||
因此,我們可以通過一個配置中心以一種科學的管理方式來統一管理相關的配置。
|
||||
因此,我們可以透過一個配置中心以一種科學的管理方式來統一管理相關的配置。
|
||||
|
||||
## 安裝
|
||||
|
||||
@ -187,9 +187,9 @@ return [
|
||||
|
||||
## 配置更新的作用範圍
|
||||
|
||||
在預設的功能實現下,是由一個 `ConfigFetcherProcess` 程序根據配置的 `interval` 來向 配置中心 Server 拉取對應 `namespace` 的配置,並通過 IPC 通訊將拉取到的新配置傳遞到各個 Worker 中,並更新到 `Hyperf\Contract\ConfigInterface` 對應的物件內。
|
||||
需要注意的是,更新的配置只會更新 `Config` 物件,故僅限應用層或業務層的配置,不涉及框架層的配置改動,因為框架層的配置改動需要重啟服務,如果您有這樣的需求,也可以通過自行實現 `ConfigFetcherProcess` 來達到目的。
|
||||
在預設的功能實現下,是由一個 `ConfigFetcherProcess` 程序根據配置的 `interval` 來向 配置中心 Server 拉取對應 `namespace` 的配置,並透過 IPC 通訊將拉取到的新配置傳遞到各個 Worker 中,並更新到 `Hyperf\Contract\ConfigInterface` 對應的物件內。
|
||||
需要注意的是,更新的配置只會更新 `Config` 物件,故僅限應用層或業務層的配置,不涉及框架層的配置改動,因為框架層的配置改動需要重啟服務,如果您有這樣的需求,也可以透過自行實現 `ConfigFetcherProcess` 來達到目的。
|
||||
|
||||
## 注意事項
|
||||
|
||||
在命令列模式時,預設不會觸發事件分發,導致無法正常獲取到相關配置,可通過新增 `--enable-event-dispatcher` 引數來開啟。
|
||||
在命令列模式時,預設不會觸發事件分發,導致無法正常獲取到相關配置,可透過新增 `--enable-event-dispatcher` 引數來開啟。
|
||||
|
@ -99,7 +99,7 @@ return [
|
||||
|
||||
## `config.php` 與 `autoload` 資料夾內的配置檔案的關係
|
||||
|
||||
`config.php` 與 `autoload` 資料夾內的配置檔案在服務啟動時都會被掃描並注入到 `Hyperf\Contract\ConfigInterface` 對應的物件中,配置的結構為一個鍵值對的大陣列,兩種配置形式不同的在於 `autoload` 內配置檔案的檔名會作為第一層 鍵(Key) 存在,而 `config.php` 內的則以您定義的為第一層,我們通過下面的例子來演示一下。
|
||||
`config.php` 與 `autoload` 資料夾內的配置檔案在服務啟動時都會被掃描並注入到 `Hyperf\Contract\ConfigInterface` 對應的物件中,配置的結構為一個鍵值對的大陣列,兩種配置形式不同的在於 `autoload` 內配置檔案的檔名會作為第一層 鍵(Key) 存在,而 `config.php` 內的則以您定義的為第一層,我們透過下面的例子來演示一下。
|
||||
我們假設存在一個 `config/autoload/client.php` 檔案,檔案內容如下:
|
||||
```php
|
||||
return [
|
||||
@ -131,9 +131,9 @@ return [
|
||||
|
||||
### 獲取配置
|
||||
|
||||
Config 元件提供了三種方式獲取配置,通過 `Hyperf\Config\Config` 物件獲取、通過 `@Value` 註解獲取和通過 `config(string $key, $default)` 函式獲取。
|
||||
Config 元件提供了三種方式獲取配置,透過 `Hyperf\Config\Config` 物件獲取、透過 `@Value` 註解獲取和透過 `config(string $key, $default)` 函式獲取。
|
||||
|
||||
#### 通過 Config 物件獲取配置
|
||||
#### 透過 Config 物件獲取配置
|
||||
|
||||
這種方式要求你已經拿到了 `Config` 物件的例項,預設物件為 `Hyperf\Config\Config`,注入例項的細節可查閱 [依賴注入](zh-tw/di.md) 章節;
|
||||
|
||||
@ -141,13 +141,13 @@ Config 元件提供了三種方式獲取配置,通過 `Hyperf\Config\Config`
|
||||
/**
|
||||
* @var \Hyperf\Contract\ConfigInterface
|
||||
*/
|
||||
// 通過 get(string $key, $default): mixed 方法獲取 $key 所對應的配置,$key 值可以通過 . 連線符定位到下級陣列,$default 則是當對應的值不存在時返回的預設值
|
||||
// 透過 get(string $key, $default): mixed 方法獲取 $key 所對應的配置,$key 值可以透過 . 連線符定位到下級陣列,$default 則是當對應的值不存在時返回的預設值
|
||||
$config->get($key,$default);
|
||||
```
|
||||
|
||||
#### 通過 `@Value` 註解獲取配置
|
||||
#### 透過 `@Value` 註解獲取配置
|
||||
|
||||
這種方式要求註解的應用物件必須是通過 [hyperf/di](https://github.com/hyperf/di) 元件建立的,注入例項的細節可查閱 [依賴注入](zh-tw/di.md) 章節,示例中我們假設 `IndexController` 就是一個已經定義好的 `Controller` 類,`Controller` 類一定是由 `DI` 容器創建出來的;
|
||||
這種方式要求註解的應用物件必須是透過 [hyperf/di](https://github.com/hyperf/di) 元件建立的,注入例項的細節可查閱 [依賴注入](zh-tw/di.md) 章節,示例中我們假設 `IndexController` 就是一個已經定義好的 `Controller` 類,`Controller` 類一定是由 `DI` 容器創建出來的;
|
||||
`@Value()` 內的字串則對應到 `$config->get($key)` 內的 `$key` 引數,在建立該物件例項時,對應的配置會自動注入到定義的類屬性中。
|
||||
|
||||
```php
|
||||
@ -167,9 +167,9 @@ class IndexController
|
||||
}
|
||||
```
|
||||
|
||||
#### 通過 config 函式獲取
|
||||
#### 透過 config 函式獲取
|
||||
|
||||
在任意地方可以通過 `config(string $key, $default)` 函式獲取對應的配置,但這樣的使用方式也就意味著您對 [hyperf/config](https://github.com/hyperf/config) 和 [hyperf/utils](https://github.com/hyperf/utils) 元件是強依賴的。
|
||||
在任意地方可以透過 `config(string $key, $default)` 函式獲取對應的配置,但這樣的使用方式也就意味著您對 [hyperf/config](https://github.com/hyperf/config) 和 [hyperf/utils](https://github.com/hyperf/utils) 元件是強依賴的。
|
||||
|
||||
### 判斷配置是否存在
|
||||
|
||||
@ -177,7 +177,7 @@ class IndexController
|
||||
/**
|
||||
* @var \Hyperf\Contract\ConfigInterface
|
||||
*/
|
||||
// 通過 has(): bool 方法判斷對應的 $key 值是否存在於配置中,$key 值可以通過 . 連線符定位到下級陣列
|
||||
// 透過 has(): bool 方法判斷對應的 $key 值是否存在於配置中,$key 值可以透過 . 連線符定位到下級陣列
|
||||
$config->has($key);
|
||||
```
|
||||
|
||||
@ -185,9 +185,9 @@ $config->has($key);
|
||||
|
||||
對於不同的執行環境使用不同的配置是一種常見的需求,比如在測試環境和生產環境的 Redis 配置不一樣,而生產環境的配置又不能提交到原始碼版本管理系統中以免資訊洩露。
|
||||
|
||||
在 Hyperf 裡我們提供了環境變數這一解決方案,通過利用 [vlucas/phpdotenv](https://github.com/vlucas/phpdotenv) 提供的環境變數解析功能,以及 `env()` 函式來獲取環境變數的值,這一需求解決起來是相當的容易。
|
||||
在 Hyperf 裡我們提供了環境變數這一解決方案,透過利用 [vlucas/phpdotenv](https://github.com/vlucas/phpdotenv) 提供的環境變數解析功能,以及 `env()` 函式來獲取環境變數的值,這一需求解決起來是相當的容易。
|
||||
|
||||
在新安裝好的 Hyperf 應用中,其根目錄會包含一個 `.env.example` 檔案。如果是通過 Composer 安裝的 Hyperf,該檔案會自動基於 `.env.example` 複製一個新檔案並命名為 `.env`。否則,需要你手動更改一下檔名。
|
||||
在新安裝好的 Hyperf 應用中,其根目錄會包含一個 `.env.example` 檔案。如果是透過 Composer 安裝的 Hyperf,該檔案會自動基於 `.env.example` 複製一個新檔案並命名為 `.env`。否則,需要你手動更改一下檔名。
|
||||
|
||||
您的 `.env` 檔案不應該提交到應用的原始碼版本管理系統中,因為每個使用你的應用的開發人員 / 伺服器可能需要有一個不同的環境配置。此外,在入侵者獲得你的原始碼倉庫的訪問權的情況下,這會導致嚴重的安全問題,因為所有敏感的資料都被一覽無餘了。
|
||||
|
||||
@ -208,7 +208,7 @@ $config->has($key);
|
||||
| null | (null) null |
|
||||
| (null) | (null) null |
|
||||
|
||||
如果你需要使用包含空格或包含其他特殊字元的環境變數,可以通過將值括在雙引號中來實現,比如:
|
||||
如果你需要使用包含空格或包含其他特殊字元的環境變數,可以透過將值括在雙引號中來實現,比如:
|
||||
|
||||
```dotenv
|
||||
APP_NAME="Hyperf Skeleton"
|
||||
@ -216,7 +216,7 @@ APP_NAME="Hyperf Skeleton"
|
||||
|
||||
### 讀取環境變數
|
||||
|
||||
我們在上面也有提到環境變數可以通過 `env()` 函式獲取,在應用開發中,環境變數只應作為配置的一個值,通過環境變數的值來覆蓋配置的值,對於應用層來說應 **只使用配置**,而不是直接使用環境變數。
|
||||
我們在上面也有提到環境變數可以透過 `env()` 函式獲取,在應用開發中,環境變數只應作為配置的一個值,透過環境變數的值來覆蓋配置的值,對於應用層來說應 **只使用配置**,而不是直接使用環境變數。
|
||||
我們舉個合理使用的例子:
|
||||
|
||||
```php
|
||||
@ -228,8 +228,8 @@ return [
|
||||
|
||||
## 釋出元件配置
|
||||
|
||||
Hyperf 採用元件化設計,在新增一些元件進來骨架專案後,我們通常會需要為新新增的元件建立對應的配置檔案,以滿足對元件的使用。Hyperf 為元件提供了一個 `元件配置釋出機制`,通過該機制,您只需通過一個 `vendor:publish` 命令即可將元件預設的配置檔案模板釋出到骨架專案中來。
|
||||
比如我們希望新增一個 `hyperf/foo` 元件 (該元件實際並不存在,僅示例) 以及該元件對應的配置檔案,在執行 `composer require hyperf/foo` 安裝之後,您可通過執行 `php bin/hyperf.php vendor:publish hyperf/foo` 來將元件預設的配置檔案,釋出到骨架專案的 `config/autoload` 資料夾內,具體要釋出的內容,由元件來定義提供。
|
||||
Hyperf 採用元件化設計,在新增一些元件進來骨架專案後,我們通常會需要為新新增的元件建立對應的配置檔案,以滿足對元件的使用。Hyperf 為元件提供了一個 `元件配置釋出機制`,透過該機制,您只需透過一個 `vendor:publish` 命令即可將元件預設的配置檔案模板釋出到骨架專案中來。
|
||||
比如我們希望新增一個 `hyperf/foo` 元件 (該元件實際並不存在,僅示例) 以及該元件對應的配置檔案,在執行 `composer require hyperf/foo` 安裝之後,您可透過執行 `php bin/hyperf.php vendor:publish hyperf/foo` 來將元件預設的配置檔案,釋出到骨架專案的 `config/autoload` 資料夾內,具體要釋出的內容,由元件來定義提供。
|
||||
|
||||
## 配置中心
|
||||
|
||||
|
@ -32,7 +32,7 @@ composer require hyperf/constants
|
||||
|
||||
### 定義列舉類
|
||||
|
||||
通過 `gen:constant` 命令可以快速的生成一個列舉類。
|
||||
透過 `gen:constant` 命令可以快速的生成一個列舉類。
|
||||
|
||||
```bash
|
||||
php bin/hyperf.php gen:constant ErrorCode
|
||||
|
@ -32,7 +32,7 @@ $kv = new KV(function () use ($clientFactory, $consulServer) {
|
||||
|
||||
### Consul ACL Token
|
||||
|
||||
#### 通過 Header 新增 Token
|
||||
#### 透過 Header 新增 Token
|
||||
|
||||
您可在呼叫方法時往 Client 傳遞 Key 為 `X-Consul-Token` 的 Header 來設定,如下所示:
|
||||
|
||||
@ -55,7 +55,7 @@ $kv = new KV(function () use ($clientFactory, $consulServer) {
|
||||
});
|
||||
```
|
||||
|
||||
#### 通過 Query 新增 Token
|
||||
#### 透過 Query 新增 Token
|
||||
|
||||
您也可在呼叫方法時往 $options 引數傳遞 Key 為 `token` 的引數來設定,這樣 Token 會跟隨 Query 一起傳遞到 Server,如下所示:
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# 控制器
|
||||
|
||||
通過控制器來處理 HTTP 請求,需要通過 `配置檔案` 或 `註解` 的形式將路由與控制器方法進行繫結,具體請查閱 [路由](zh-tw/router.md) 章節。
|
||||
透過控制器來處理 HTTP 請求,需要透過 `配置檔案` 或 `註解` 的形式將路由與控制器方法進行繫結,具體請查閱 [路由](zh-tw/router.md) 章節。
|
||||
對於 `請求(Request)` 與 `響應(Response)`,Hyperf 提供了 `Hyperf\HttpServer\Contract\RequestInterface` 和 `Hyperf\HttpServer\Contract\ResponseInterface` 方便您獲取入參和返回資料,關於 [請求](zh-tw/request.md) 與 [響應](zh-tw/response.md) 的詳細內容請查閱對應的章節。
|
||||
|
||||
## 編寫控制器
|
||||
@ -17,7 +17,7 @@ use Hyperf\HttpServer\Contract\ResponseInterface;
|
||||
|
||||
class IndexController
|
||||
{
|
||||
// 在引數上通過定義 RequestInterface 和 ResponseInterface 來獲取相關物件,物件會被依賴注入容器自動注入
|
||||
// 在引數上透過定義 RequestInterface 和 ResponseInterface 來獲取相關物件,物件會被依賴注入容器自動注入
|
||||
public function index(RequestInterface $request, ResponseInterface $response)
|
||||
{
|
||||
$target = $request->input('target', 'World');
|
||||
@ -28,7 +28,7 @@ class IndexController
|
||||
|
||||
> 我們假設該 `Controller` 已經通過了配置檔案的形式定義了路由為 `/`,當然您也可以使用註解路由
|
||||
|
||||
通過 `cURL` 呼叫該地址,即可看到返回的內容。
|
||||
透過 `cURL` 呼叫該地址,即可看到返回的內容。
|
||||
|
||||
```bash
|
||||
$ curl 'http://127.0.0.1:9501/?target=Hyperf'
|
||||
@ -39,4 +39,4 @@ Hello Hyperf.
|
||||
|
||||
在傳統的 PHP-FPM 的框架裡,會習慣提供一個 `AbstractController` 或其它命名的 `Controller 抽象父類`,然後定義的 `Controller` 需要繼承它用於獲取一些請求資料或進行一些返回操作,在 Hyperf 裡是 **不能這樣做** 的,因為在 Hyperf 內絕大部分的物件包括 `Controller` 都是以 `單例(Singleton)` 形式存在的,這也是為了更好的複用物件,而對於與請求相關的資料在協程下也是需要儲存到 `協程上下文(Context)` 內的,所以在編寫程式碼時請務必注意 **不要** 將單個請求相關的資料儲存在類屬性內,包括非靜態屬性。
|
||||
|
||||
當然如果非要通過類屬性來儲存請求資料的話,也不是沒有辦法的,我們可以注意到我們獲取 `請求(Request)` 與 `響應(Response)` 物件時是通過注入 `Hyperf\HttpServer\Contract\RequestInterface` 和 `Hyperf\HttpServer\Contract\ResponseInterface` 來獲取的,那對應的物件不也是個單例嗎?這裡是如何做到協程安全的呢?就 `RequestInterface` 來舉例,對應的 `Hyperf\HttpServer\Request` 物件內部在獲取 `PSR-7 請求物件` 時,都是從 `協程上下文(Context)` 獲取的,所以實際使用的類僅僅是一個代理類,實際呼叫的都是從 `協程上下文(Context)` 中獲取的。
|
||||
當然如果非要透過類屬性來儲存請求資料的話,也不是沒有辦法的,我們可以注意到我們獲取 `請求(Request)` 與 `響應(Response)` 物件時是透過注入 `Hyperf\HttpServer\Contract\RequestInterface` 和 `Hyperf\HttpServer\Contract\ResponseInterface` 來獲取的,那對應的物件不也是個單例嗎?這裡是如何做到協程安全的呢?就 `RequestInterface` 來舉例,對應的 `Hyperf\HttpServer\Request` 物件內部在獲取 `PSR-7 請求物件` 時,都是從 `協程上下文(Context)` 獲取的,所以實際使用的類僅僅是一個代理類,實際呼叫的都是從 `協程上下文(Context)` 中獲取的。
|
||||
|
@ -6,7 +6,7 @@ Hyperf 是運行於 `Swoole 4` 的協程和 `Swow` 協程之上的,這也是 H
|
||||
|
||||
### PHP-FPM 的運作模式
|
||||
|
||||
在聊協程是什麼之前,我們先聊聊傳統 `PHP-FPM` 架構的運作模式,`PHP-FPM` 是一個多程序的 `FastCGI` 管理程式,是絕大多數 `PHP` 應用所使用的執行模式。假設我們使用 `Nginx` 提供 `HTTP` 服務(`Apache` 同理),所有客戶端發起的請求最先抵達的都是 `Nginx`,然後 `Nginx` 通過 `FastCGI` 協議將請求轉發給 `PHP-FPM` 處理,`PHP-FPM` 的 `Worker 程序` 會搶佔式的獲得 CGI 請求進行處理,這個處理指的就是,等待 `PHP` 指令碼的解析,等待業務處理的結果返回,完成後回收子程序,這整個的過程是阻塞等待的,也就意味著 `PHP-FPM` 的程序數有多少能處理的請求也就是多少,假設 `PHP-FPM` 有 `200` 個 `Worker 程序`,一個請求將耗費 `1` 秒的時間,那麼簡單的來說整個伺服器理論上最多可以處理的請求也就是 `200` 個,`QPS` 即為 `200/s`,在高併發的場景下,這樣的效能往往是不夠的,儘管可以利用 `Nginx` 作為負載均衡配合多臺 `PHP-FPM` 伺服器來提供服務,但由於 `PHP-FPM` 的阻塞等待的工作模型,一個請求會佔用至少一個 `MySQL` 連線,多節點高併發下會產生大量的 `MySQL` 連線,而 `MySQL` 的最大連線數預設值為 `100`,儘管可以修改,但顯而易見該模式沒法很好的應對高併發的場景。
|
||||
在聊協程是什麼之前,我們先聊聊傳統 `PHP-FPM` 架構的運作模式,`PHP-FPM` 是一個多程序的 `FastCGI` 管理程式,是絕大多數 `PHP` 應用所使用的執行模式。假設我們使用 `Nginx` 提供 `HTTP` 服務(`Apache` 同理),所有客戶端發起的請求最先抵達的都是 `Nginx`,然後 `Nginx` 透過 `FastCGI` 協議將請求轉發給 `PHP-FPM` 處理,`PHP-FPM` 的 `Worker 程序` 會搶佔式的獲得 CGI 請求進行處理,這個處理指的就是,等待 `PHP` 指令碼的解析,等待業務處理的結果返回,完成後回收子程序,這整個的過程是阻塞等待的,也就意味著 `PHP-FPM` 的程序數有多少能處理的請求也就是多少,假設 `PHP-FPM` 有 `200` 個 `Worker 程序`,一個請求將耗費 `1` 秒的時間,那麼簡單的來說整個伺服器理論上最多可以處理的請求也就是 `200` 個,`QPS` 即為 `200/s`,在高併發的場景下,這樣的效能往往是不夠的,儘管可以利用 `Nginx` 作為負載均衡配合多臺 `PHP-FPM` 伺服器來提供服務,但由於 `PHP-FPM` 的阻塞等待的工作模型,一個請求會佔用至少一個 `MySQL` 連線,多節點高併發下會產生大量的 `MySQL` 連線,而 `MySQL` 的最大連線數預設值為 `100`,儘管可以修改,但顯而易見該模式沒法很好的應對高併發的場景。
|
||||
|
||||
### 非同步非阻塞系統
|
||||
|
||||
@ -66,39 +66,39 @@ $db->connect($config, function ($db, $r) {
|
||||
|
||||
在 `Hyperf` 中我們已經為您處理好了這一切,您只需關注 `\Swoole\Runtime::enableCoroutine()` 仍無法協程化的阻塞程式碼即可。
|
||||
|
||||
### 不能通過全域性變數儲存狀態
|
||||
### 不能透過全域性變數儲存狀態
|
||||
|
||||
在 `Swoole` 的持久化應用下,一個 `Worker` 內的全域性變數是 `Worker` 內共享的,而從協程的介紹我們可以知道同一個 `Worker` 內還會存在多個協程並存在協程切換,也就意味著一個 `Worker` 會在一個時間週期內同時處理多個協程(或直接理解為請求)的程式碼,也就意味著如果使用了全域性變數來儲存狀態可能會被多個協程所使用,也就是說不同的請求之間可能會混淆資料,這裡的全域性變數指的是 `$_GET/$_POST/$_REQUEST/$_SESSION/$_COOKIE/$_SERVER`等`$_`開頭的變數、`global` 變數,以及 `static` 靜態屬性。
|
||||
那麼當我們需要使用到這些特性時應該怎麼辦?
|
||||
|
||||
對於全域性變數,均是跟隨著一個 `請求(Request)` 而產生的,而 `Hyperf` 的 `請求(Request)/響應(Response)` 是由 [hyperf/http-message](https://github.com/hyperf/http-message) 通過實現 [PSR-7](https://www.php-fig.org/psr/psr-7/) 處理的,故所有的全域性變數均可以在 `請求(Request)` 物件中得到相關的值;
|
||||
對於全域性變數,均是跟隨著一個 `請求(Request)` 而產生的,而 `Hyperf` 的 `請求(Request)/響應(Response)` 是由 [hyperf/http-message](https://github.com/hyperf/http-message) 透過實現 [PSR-7](https://www.php-fig.org/psr/psr-7/) 處理的,故所有的全域性變數均可以在 `請求(Request)` 物件中得到相關的值;
|
||||
|
||||
對於 `global` 變數和 `static` 變數,在 `PHP-FPM` 模式下,本質都是存活於一個請求生命週期內的,而在 `Hyperf` 內因為是 `CLI` 應用,會存在 `全域性週期` 和 `請求週期(協程週期)` 兩種長生命週期。
|
||||
- 全域性週期,我們只需要建立一個靜態變數供全域性呼叫即可,靜態變數意味著在服務啟動後,任意協程和程式碼邏輯均共享此靜態變數內的資料,也就意味著存放的資料不能是特別服務於某一個請求或某一個協程;
|
||||
- 協程週期,由於 `Hyperf` 會為每個請求自動建立一個協程來處理,那麼一個協程週期在此也可以理解為一個請求週期,在協程內,所有的狀態資料均應存放於 `Hyperf\Context\Context` 類中,通過該類的 `get`、`set` 來讀取和儲存任意結構的資料,這個 `Context(協程上下文)` 類在執行任意協程時讀取或儲存的資料都是僅限對應的協程的,同時在協程結束時也會自動銷燬相關的上下文資料。
|
||||
- 協程週期,由於 `Hyperf` 會為每個請求自動建立一個協程來處理,那麼一個協程週期在此也可以理解為一個請求週期,在協程內,所有的狀態資料均應存放於 `Hyperf\Context\Context` 類中,透過該類的 `get`、`set` 來讀取和儲存任意結構的資料,這個 `Context(協程上下文)` 類在執行任意協程時讀取或儲存的資料都是僅限對應的協程的,同時在協程結束時也會自動銷燬相關的上下文資料。
|
||||
|
||||
### 最大協程數限制
|
||||
|
||||
對 `Swoole Server` 通過 `set` 方法設定 `max_coroutine` 引數,用於配置一個 `Worker` 程序最多可存在的協程數量。因為隨著 `Worker` 程序處理的協程數目的增加,其對應占用的記憶體也會隨之增加,為了避免超出 `PHP` 的 `memory_limit` 限制,請根據實際業務的壓測結果設定該值,`Swoole` 的預設值為 `100000`( `Swoole` 版本小於 `v4.4.0-beta` 時預設值為 `3000` ), 在 `hyperf-skeleton` 專案中預設設定為 `100000`。
|
||||
對 `Swoole Server` 透過 `set` 方法設定 `max_coroutine` 引數,用於配置一個 `Worker` 程序最多可存在的協程數量。因為隨著 `Worker` 程序處理的協程數目的增加,其對應占用的記憶體也會隨之增加,為了避免超出 `PHP` 的 `memory_limit` 限制,請根據實際業務的壓測結果設定該值,`Swoole` 的預設值為 `100000`( `Swoole` 版本小於 `v4.4.0-beta` 時預設值為 `3000` ), 在 `hyperf-skeleton` 專案中預設設定為 `100000`。
|
||||
|
||||
## 使用協程
|
||||
|
||||
### 建立一個協程
|
||||
|
||||
只需通過 `co(callable $callable)` 或 `go(callable $callable)` 函式或 `Hyperf\Utils\Coroutine::create(callable $callable)` 即可建立一個協程,協程內可以使用協程相關的方法和客戶端。
|
||||
只需透過 `co(callable $callable)` 或 `go(callable $callable)` 函式或 `Hyperf\Utils\Coroutine::create(callable $callable)` 即可建立一個協程,協程內可以使用協程相關的方法和客戶端。
|
||||
|
||||
### 判斷當前是否處於協程環境內
|
||||
|
||||
在一些情況下我們希望判斷一些當前是否運行於協程環境內,對於一些相容協程環境與非協程環境的程式碼來說會作為一個判斷的依據,我們可以通過 `Hyperf\Utils\Coroutine::inCoroutine(): bool` 方法來得到結果。
|
||||
在一些情況下我們希望判斷一些當前是否運行於協程環境內,對於一些相容協程環境與非協程環境的程式碼來說會作為一個判斷的依據,我們可以透過 `Hyperf\Utils\Coroutine::inCoroutine(): bool` 方法來得到結果。
|
||||
|
||||
### 獲得當前協程的 ID
|
||||
|
||||
在一些情況下,我們需要根據 `協程 ID` 去做一些邏輯,比如 `協程上下文` 之類的邏輯,可以通過 `Hyperf\Utils\Coroutine::id(): int` 獲得當前的 `協程 ID`,如不處於協程環境下,會返回 `-1`。
|
||||
在一些情況下,我們需要根據 `協程 ID` 去做一些邏輯,比如 `協程上下文` 之類的邏輯,可以透過 `Hyperf\Utils\Coroutine::id(): int` 獲得當前的 `協程 ID`,如不處於協程環境下,會返回 `-1`。
|
||||
|
||||
### Channel 通道
|
||||
|
||||
類似於 `Go` 語言的 `chan`,`Channel` 可為多生產者協程和多消費者協程模式提供支援。底層自動實現了協程的切換和排程。 `Channel` 與 `PHP` 的陣列類似,僅佔用記憶體,沒有其他額外的資源申請,所有操作均為記憶體操作,無 `I/O` 消耗,使用方法與 `SplQueue` 佇列類似。
|
||||
`Channel` 主要用於協程間通訊,當我們希望從一個協程裡返回一些資料到另一個協程時,就可通過 `Channel` 來進行傳遞。
|
||||
`Channel` 主要用於協程間通訊,當我們希望從一個協程裡返回一些資料到另一個協程時,就可透過 `Channel` 來進行傳遞。
|
||||
|
||||
主要方法:
|
||||
- `Channel->push` :當佇列中有其他協程正在等待 `pop` 資料時,自動按順序喚醒一個消費者協程。當佇列已滿時自動 `yield` 讓出控制權,等待其他協程消費資料
|
||||
@ -119,12 +119,12 @@ co(function () {
|
||||
|
||||
### Defer 特性
|
||||
|
||||
當我們希望在協程結束時執行一些程式碼時,可以通過 `defer(callable $callable)` 函式或 `Hyperf\Coroutine::defer(callable $callable)` 將一段函式以 `棧(stack)` 的形式儲存起來,`棧(stack)` 內的函式會在當前協程結束時以 `先進後出` 的流程逐個執行。
|
||||
當我們希望在協程結束時執行一些程式碼時,可以透過 `defer(callable $callable)` 函式或 `Hyperf\Coroutine::defer(callable $callable)` 將一段函式以 `棧(stack)` 的形式儲存起來,`棧(stack)` 內的函式會在當前協程結束時以 `先進後出` 的流程逐個執行。
|
||||
|
||||
### WaitGroup 特性
|
||||
|
||||
`WaitGroup` 是基於 `Channel` 衍生出來的一個特性,如果接觸過 `Go` 語言,我們都會知道 `WaitGroup` 這一特性,在 `Hyperf` 裡,`WaitGroup` 的用途是使得主協程一直阻塞等待直到所有相關的子協程都已經完成了任務後再繼續執行,這裡說到的阻塞等待是僅對於主協程(即當前協程)來說的,並不會阻塞當前程序。
|
||||
我們通過一段程式碼來演示該特性:
|
||||
我們透過一段程式碼來演示該特性:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -151,7 +151,7 @@ $wg->wait();
|
||||
|
||||
### Parallel 特性
|
||||
|
||||
`Parallel` 特性是 Hyperf 基於 `WaitGroup` 特性抽象出來的一個更便捷的使用方法,我們通過一段程式碼來演示一下。
|
||||
`Parallel` 特性是 Hyperf 基於 `WaitGroup` 特性抽象出來的一個更便捷的使用方法,我們透過一段程式碼來演示一下。
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -179,8 +179,8 @@ try{
|
||||
```
|
||||
> 注意 `Hyperf\Utils\Exception\ParallelExecutionException` 異常僅在 1.1.6 版本和更新的版本下會丟擲
|
||||
|
||||
通過上面的程式碼我們可以看到僅花了 `1` 秒就得到了兩個不同的協程的 `ID`,在呼叫 `add(callable $callable)` 的時候 `Parallel` 類會為之自動建立一個協程,並加入到 `WaitGroup` 的排程去。
|
||||
不僅如此,我們還可以通過 `parallel(array $callables)` 函式進行更進一步的簡化上面的程式碼,達到同樣的目的,下面為簡化後的程式碼。
|
||||
透過上面的程式碼我們可以看到僅花了 `1` 秒就得到了兩個不同的協程的 `ID`,在呼叫 `add(callable $callable)` 的時候 `Parallel` 類會為之自動建立一個協程,並加入到 `WaitGroup` 的排程去。
|
||||
不僅如此,我們還可以透過 `parallel(array $callables)` 函式進行更進一步的簡化上面的程式碼,達到同樣的目的,下面為簡化後的程式碼。
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -203,7 +203,7 @@ $result = parallel([
|
||||
|
||||
#### 限制 Parallel 最大同時執行的協程數
|
||||
|
||||
當我們新增到 `Parallel` 裡的任務有很多時,假設都是一些請求任務,那麼一瞬間發出全部請求很有可能會導致對端服務因為一瞬間接收到了大量的請求而處理不過來,有宕機的風險,所以需要對對端進行適當的保護,但我們又希望可以通過 `Parallel` 機制來加速這些請求的耗時,那麼可以通過在例項化 `Parallel` 物件時傳遞第一個引數,來設定最大執行的協程數,比如我們希望最大設定的協程數為 `5` ,也就意味著 `Parallel` 裡最多隻會有 `5` 個協程在執行,只有當 `5` 個裡有協程完成結束後,後續的協程才會繼續啟動,直至所有協程完成任務,示例程式碼如下:
|
||||
當我們新增到 `Parallel` 裡的任務有很多時,假設都是一些請求任務,那麼一瞬間發出全部請求很有可能會導致對端服務因為一瞬間接收到了大量的請求而處理不過來,有宕機的風險,所以需要對對端進行適當的保護,但我們又希望可以透過 `Parallel` 機制來加速這些請求的耗時,那麼可以透過在例項化 `Parallel` 物件時傳遞第一個引數,來設定最大執行的協程數,比如我們希望最大設定的協程數為 `5` ,也就意味著 `Parallel` 裡最多隻會有 `5` 個協程在執行,只有當 `5` 個裡有協程完成結束後,後續的協程才會繼續啟動,直至所有協程完成任務,示例程式碼如下:
|
||||
|
||||
```php
|
||||
use Hyperf\Utils\Exception\ParallelExecutionException;
|
||||
@ -249,11 +249,11 @@ for ($i = 0; $i < 15; ++$i) {
|
||||
### 協程上下文
|
||||
|
||||
由於同一個程序內協程間是記憶體共享的,但協程的執行/切換是非順序的,也就意味著我們很難掌控當前的協程是哪一個**(事實上可以,但通常沒人這麼幹)**,所以我們需要在發生協程切換時能夠同時切換對應的上下文。
|
||||
在 `Hyperf` 裡實現協程的上下文管理將非常簡單,基於 `Hyperf\Context\Context` 類的 `set(string $id, $value)`、`get(string $id, $default = null)`、`has(string $id)`、`override(string $id, \Closure $closure)` 靜態方法即可完成上下文資料的管理,通過這些方法設定和獲取的值,都僅限於當前的協程,在協程結束時,對應的上下文也會自動跟隨釋放掉,無需手動管理,無需擔憂記憶體洩漏的風險。
|
||||
在 `Hyperf` 裡實現協程的上下文管理將非常簡單,基於 `Hyperf\Context\Context` 類的 `set(string $id, $value)`、`get(string $id, $default = null)`、`has(string $id)`、`override(string $id, \Closure $closure)` 靜態方法即可完成上下文資料的管理,透過這些方法設定和獲取的值,都僅限於當前的協程,在協程結束時,對應的上下文也會自動跟隨釋放掉,無需手動管理,無需擔憂記憶體洩漏的風險。
|
||||
|
||||
#### Hyperf\Context\Context::set()
|
||||
|
||||
通過呼叫 `set(string $id, $value)` 方法儲存一個值到當前協程的上下文中,如下:
|
||||
透過呼叫 `set(string $id, $value)` 方法儲存一個值到當前協程的上下文中,如下:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -266,7 +266,7 @@ $foo = Context::set('foo', 'bar');
|
||||
|
||||
#### Hyperf\Context\Context::get()
|
||||
|
||||
通過呼叫 `get(string $id, $default = null)` 方法可從當前協程的上下文中取出一個以 `$id` 為 `key` 儲存的值,如不存在則返回 `$default` ,如下:
|
||||
透過呼叫 `get(string $id, $default = null)` 方法可從當前協程的上下文中取出一個以 `$id` 為 `key` 儲存的值,如不存在則返回 `$default` ,如下:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -278,7 +278,7 @@ $foo = Context::get('foo', 'bar');
|
||||
|
||||
#### Hyperf\Context\Context::has()
|
||||
|
||||
通過呼叫 `has(string $id)` 方法可判斷當前協程的上下文中是否存在以 `$id` 為 `key` 儲存的值,如存在則返回 `true`,不存在則返回 `false`,如下:
|
||||
透過呼叫 `has(string $id)` 方法可判斷當前協程的上下文中是否存在以 `$id` 為 `key` 儲存的值,如存在則返回 `true`,不存在則返回 `false`,如下:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -290,7 +290,7 @@ $foo = Context::has('foo');
|
||||
|
||||
#### Hyperf\Context\Context::override()
|
||||
|
||||
當我們需要做一些複雜的上下文處理,比如先判斷一個 `key` 是否存在,如果存在則取出 `value` 來再對 `value` 進行某些修改,然後再將 `value` 設定回上下文容器中,此時會有比較繁雜的判斷條件,可直接通過呼叫 `override` 方法來實現這個邏輯,如下:
|
||||
當我們需要做一些複雜的上下文處理,比如先判斷一個 `key` 是否存在,如果存在則取出 `value` 來再對 `value` 進行某些修改,然後再將 `value` 設定回上下文容器中,此時會有比較繁雜的判斷條件,可直接透過呼叫 `override` 方法來實現這個邏輯,如下:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
@ -1,6 +1,6 @@
|
||||
# 定時任務
|
||||
|
||||
通常來說,執行定時任務會通過 Linux 的 `crontab` 命令來實現,但現實情況下,並不是所有開發人員都能夠擁有生產環境的伺服器去設定定時任務的,這裡 [hyperf/crontab](https://github.com/hyperf/crontab) 元件為您提供了一個 `秒級` 定時任務功能,只需通過簡單的定義即可完成一個定時任務的定義。
|
||||
通常來說,執行定時任務會透過 Linux 的 `crontab` 命令來實現,但現實情況下,並不是所有開發人員都能夠擁有生產環境的伺服器去設定定時任務的,這裡 [hyperf/crontab](https://github.com/hyperf/crontab) 元件為您提供了一個 `秒級` 定時任務功能,只需透過簡單的定義即可完成一個定時任務的定義。
|
||||
|
||||
# 安裝
|
||||
|
||||
@ -35,7 +35,7 @@ return [
|
||||
|
||||
## 定義定時任務
|
||||
|
||||
### 通過配置檔案定義
|
||||
### 透過配置檔案定義
|
||||
|
||||
您可於 `config/autoload/crontab.php` 的配置檔案內配置您所有的定時任務,檔案返回一個 `Hyperf\Crontab\Crontab[]` 結構的陣列,如配置檔案不存在可自行建立:
|
||||
|
||||
@ -45,7 +45,7 @@ return [
|
||||
use Hyperf\Crontab\Crontab;
|
||||
return [
|
||||
'enable' => true,
|
||||
// 通過配置檔案定義的定時任務
|
||||
// 透過配置檔案定義的定時任務
|
||||
'crontab' => [
|
||||
// Callback型別定時任務(預設)
|
||||
(new Crontab())->setName('Foo')->setRule('* * * * *')->setCallback([App\Task\FooTask::class, 'execute'])->setMemo('這是一個示例的定時任務'),
|
||||
@ -61,9 +61,9 @@ return [
|
||||
];
|
||||
```
|
||||
|
||||
### 通過註解定義
|
||||
### 透過註解定義
|
||||
|
||||
通過 `@Crontab` 註解可以快速完成對一個任務的定義,以下的定義示例與配置檔案定義所達到的目的都是一樣的。定義一個名為 `Foo` 每分鐘執行一次 `App\Task\FooTask::execute()` 的定時任務。
|
||||
透過 `@Crontab` 註解可以快速完成對一個任務的定義,以下的定義示例與配置檔案定義所達到的目的都是一樣的。定義一個名為 `Foo` 每分鐘執行一次 `App\Task\FooTask::execute()` 的定時任務。
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -104,7 +104,7 @@ class FooTask
|
||||
|
||||
#### callback
|
||||
|
||||
定時任務的執行回撥,即定時任務實際執行的程式碼,在通過配置檔案定義時,這裡需要傳遞一個 `[$class, $method]` 的陣列,`$class` 為一個類的全稱,`$method` 為 `$class` 內的一個 `public` 方法。當通過註解定義時,只需要提供一個當前類內的 `public` 方法的方法名即可,如果當前類只有一個 `public` 方法,您甚至可以不提供該屬性。
|
||||
定時任務的執行回撥,即定時任務實際執行的程式碼,在透過配置檔案定義時,這裡需要傳遞一個 `[$class, $method]` 的陣列,`$class` 為一個類的全稱,`$method` 為 `$class` 內的一個 `public` 方法。當透過註解定義時,只需要提供一個當前類內的 `public` 方法的方法名即可,如果當前類只有一個 `public` 方法,您甚至可以不提供該屬性。
|
||||
|
||||
#### singleton
|
||||
|
||||
@ -199,13 +199,13 @@ class EchoCrontab
|
||||
|
||||
### 排程分發策略
|
||||
|
||||
定時任務在設計上允許通過不同的策略來排程分發執行任務,目前僅提供了 `多程序執行策略`、`協程執行策略` 兩種策略,預設為 `多程序執行策略`,後面的迭代會增加更多更強的策略。
|
||||
定時任務在設計上允許透過不同的策略來排程分發執行任務,目前僅提供了 `多程序執行策略`、`協程執行策略` 兩種策略,預設為 `多程序執行策略`,後面的迭代會增加更多更強的策略。
|
||||
|
||||
> 當使用協程風格服務時,請使用 協程執行策略。
|
||||
|
||||
#### 更改排程分發策略
|
||||
|
||||
通過在 `config/autoload/dependencies.php` 更改 `Hyperf\Crontab\Strategy\StrategyInterface` 介面類所對應的例項來更改目前所使用的策略,預設情況下使用 `Worker 程序執行策略`,對應的類為 `Hyperf\Crontab\Strategy\WorkerStrategy`,如我們希望更改策略為一個新的策略,比如為 `App\Crontab\Strategy\FooStrategy`,那麼如下:
|
||||
透過在 `config/autoload/dependencies.php` 更改 `Hyperf\Crontab\Strategy\StrategyInterface` 介面類所對應的例項來更改目前所使用的策略,預設情況下使用 `Worker 程序執行策略`,對應的類為 `Hyperf\Crontab\Strategy\WorkerStrategy`,如我們希望更改策略為一個新的策略,比如為 `App\Crontab\Strategy\FooStrategy`,那麼如下:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -218,19 +218,19 @@ return [
|
||||
|
||||
策略類:`Hyperf\Crontab\Strategy\WorkerStrategy`
|
||||
|
||||
預設情況下使用此策略,即為 `CrontabDispatcherProcess` 程序解析定時任務,並通過程序間通訊輪詢傳遞執行任務到各個 `Worker` 程序中,由各個 `Worker` 程序以協程來實際執行執行任務。
|
||||
預設情況下使用此策略,即為 `CrontabDispatcherProcess` 程序解析定時任務,並透過程序間通訊輪詢傳遞執行任務到各個 `Worker` 程序中,由各個 `Worker` 程序以協程來實際執行執行任務。
|
||||
|
||||
##### TaskWorker 程序執行策略
|
||||
|
||||
策略類:`Hyperf\Crontab\Strategy\TaskWorkerStrategy`
|
||||
|
||||
此策略為 `CrontabDispatcherProcess` 程序解析定時任務,並通過程序間通訊輪詢傳遞執行任務到各個 `TaskWorker` 程序中,由各個 `TaskWorker` 程序以協程來實際執行執行任務,使用此策略需注意 `TaskWorker` 程序是否配置了支援協程。
|
||||
此策略為 `CrontabDispatcherProcess` 程序解析定時任務,並透過程序間通訊輪詢傳遞執行任務到各個 `TaskWorker` 程序中,由各個 `TaskWorker` 程序以協程來實際執行執行任務,使用此策略需注意 `TaskWorker` 程序是否配置了支援協程。
|
||||
|
||||
##### 多程序執行策略
|
||||
|
||||
策略類:`Hyperf\Crontab\Strategy\ProcessStrategy`
|
||||
|
||||
此策略為 `CrontabDispatcherProcess` 程序解析定時任務,並通過程序間通訊輪詢傳遞執行任務到各個 `Worker` 程序和 `TaskWorker` 程序中,由各個程序以協程來實際執行執行任務,使用此策略需注意 `TaskWorker` 程序是否配置了支援協程。
|
||||
此策略為 `CrontabDispatcherProcess` 程序解析定時任務,並透過程序間通訊輪詢傳遞執行任務到各個 `Worker` 程序和 `TaskWorker` 程序中,由各個程序以協程來實際執行執行任務,使用此策略需注意 `TaskWorker` 程序是否配置了支援協程。
|
||||
|
||||
##### 協程執行策略
|
||||
|
||||
|
@ -24,7 +24,7 @@ composer require hyperf/dag
|
||||
|
||||
假設我們有一系列任務,拓撲結構如上圖所示,頂點代表任務,邊緣代表依賴關係。(A 完成後才能完成 B、C、D,B 完成後才能完成 H、E、F...)
|
||||
|
||||
通過 `hyperf/dag` 可以使用如下方式構建 `DAG` 並執行。
|
||||
透過 `hyperf/dag` 可以使用如下方式構建 `DAG` 並執行。
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -111,7 +111,7 @@ assert($results[$b->key] === 2);
|
||||
\Hyperf\Dag\Vertex::make(function() { return 'hello'; }, "greeting");
|
||||
```
|
||||
|
||||
除了使用閉包函式定義任務外,還可以使用實現了 `\Hyperf\Dag\Runner` 介面的類來定義,並通過 `Vertex::of` 將其轉化為一個頂點。
|
||||
除了使用閉包函式定義任務外,還可以使用實現了 `\Hyperf\Dag\Runner` 介面的類來定義,並透過 `Vertex::of` 將其轉化為一個頂點。
|
||||
|
||||
```php
|
||||
class MyJob implements \Hyperf\Dag\Runner {
|
||||
|
@ -10,7 +10,7 @@ composer require hyperf/db
|
||||
|
||||
## 釋出元件配置
|
||||
|
||||
該元件的配置檔案位於 `config/autoload/db.php`,如果檔案不存在,可通過下面的命令來將配置檔案釋出到骨架去:
|
||||
該元件的配置檔案位於 `config/autoload/db.php`,如果檔案不存在,可透過下面的命令來將配置檔案釋出到骨架去:
|
||||
|
||||
```bash
|
||||
php bin/hyperf.php vendor:publish hyperf/db
|
||||
@ -85,7 +85,7 @@ $res = DB::query('SELECT * FROM `user` WHERE gender = ?;', [1]);
|
||||
|
||||
> 此種方式可以允許使用者直接操作底層的 `PDO` 或者 `MySQL`,所以需要自己處理相容問題
|
||||
|
||||
比如我們想執行某些查詢,使用不同的 `fetch mode`,則可以通過以下方式,自定義自己的方法
|
||||
比如我們想執行某些查詢,使用不同的 `fetch mode`,則可以透過以下方式,自定義自己的方法
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
@ -1,6 +1,6 @@
|
||||
# 模型建立指令碼
|
||||
|
||||
Hyperf 提供了建立模型的命令,您可以很方便的根據資料表建立對應模型。命令通過 `AST` 生成模型,所以當您增加了某些方法後,也可以使用指令碼方便的重置模型。
|
||||
Hyperf 提供了建立模型的命令,您可以很方便的根據資料表建立對應模型。命令透過 `AST` 生成模型,所以當您增加了某些方法後,也可以使用指令碼方便的重置模型。
|
||||
|
||||
```bash
|
||||
php bin/hyperf.php gen:model table_name
|
||||
@ -186,7 +186,7 @@ class UserExt extends Model
|
||||
|
||||
```
|
||||
|
||||
這時候,我們就可以通過重寫 `ModelUpdateVisitor`,修改這一特性。
|
||||
這時候,我們就可以透過重寫 `ModelUpdateVisitor`,修改這一特性。
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
# 生成遷移
|
||||
|
||||
通過 `gen:migration` 生成一個遷移檔案,命令後面跟的是一個檔名引數,通常為這個遷移要打算做的事情。
|
||||
透過 `gen:migration` 生成一個遷移檔案,命令後面跟的是一個檔名引數,通常為這個遷移要打算做的事情。
|
||||
|
||||
```bash
|
||||
php bin/hyperf.php gen:migration create_users_table
|
||||
@ -59,7 +59,7 @@ class CreateUsersTable extends Migration
|
||||
|
||||
# 執行遷移
|
||||
|
||||
通過執行 `migrate` 命令執行所有尚未完成的遷移檔案:
|
||||
透過執行 `migrate` 命令執行所有尚未完成的遷移檔案:
|
||||
|
||||
```bash
|
||||
php bin/hyperf.php migrate
|
||||
@ -75,7 +75,7 @@ php bin/hyperf.php migrate --force
|
||||
|
||||
## 回滾遷移
|
||||
|
||||
若您希望回滾最後一次的遷移,可以通過 `migrate:rollback` 命令回滾最後一次的遷移,注意一次遷移可能會包含多個遷移檔案:
|
||||
若您希望回滾最後一次的遷移,可以透過 `migrate:rollback` 命令回滾最後一次的遷移,注意一次遷移可能會包含多個遷移檔案:
|
||||
|
||||
```bash
|
||||
php bin/hyperf.php migrate:rollback
|
||||
@ -87,7 +87,7 @@ php bin/hyperf.php migrate:rollback
|
||||
php bin/hyperf.php migrate:rollback --step=5
|
||||
```
|
||||
|
||||
如果您希望回滾所有的遷移,可以通過 `migrate:reset` 來回滾:
|
||||
如果您希望回滾所有的遷移,可以透過 `migrate:reset` 來回滾:
|
||||
|
||||
```bash
|
||||
php bin/hyperf.php migrate:reset
|
||||
@ -104,7 +104,7 @@ php bin/hyperf.php migrate:refresh
|
||||
php bin/hyperf.php migrate:refresh --seed
|
||||
```
|
||||
|
||||
通過 `--step` 引數指定回滾和重建次數,比如以下命令將回滾並重新執行最後 5 次遷移:
|
||||
透過 `--step` 引數指定回滾和重建次數,比如以下命令將回滾並重新執行最後 5 次遷移:
|
||||
|
||||
```bash
|
||||
php bin/hyperf.php migrate:refresh --step=5
|
||||
@ -112,7 +112,7 @@ php bin/hyperf.php migrate:refresh --step=5
|
||||
|
||||
## 重建資料庫
|
||||
|
||||
通過 `migrate:fresh` 命令可以高效地重建整個資料庫,這個命令會先刪除所有的資料庫,然後再執行 `migrate` 命令:
|
||||
透過 `migrate:fresh` 命令可以高效地重建整個資料庫,這個命令會先刪除所有的資料庫,然後再執行 `migrate` 命令:
|
||||
|
||||
```bash
|
||||
php bin/hyperf.php migrate:fresh
|
||||
@ -123,11 +123,11 @@ php bin/hyperf.php migrate:fresh --seed
|
||||
|
||||
# 資料表
|
||||
|
||||
在遷移檔案中主要通過 `Hyperf\Database\Schema\Schema` 類來定義資料表和管理遷移流程。
|
||||
在遷移檔案中主要透過 `Hyperf\Database\Schema\Schema` 類來定義資料表和管理遷移流程。
|
||||
|
||||
## 建立資料表
|
||||
|
||||
通過 `create` 方法來建立新的資料庫表。 `create` 方法接受兩個引數:第一個引數為資料表的名稱,第二個引數是一個 `閉包(Closure)`,此閉包會接收一個用於定義新資料表的 `Hyperf\Database\Schema\Blueprint` 物件:
|
||||
透過 `create` 方法來建立新的資料庫表。 `create` 方法接受兩個引數:第一個引數為資料表的名稱,第二個引數是一個 `閉包(Closure)`,此閉包會接收一個用於定義新資料表的 `Hyperf\Database\Schema\Blueprint` 物件:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -163,7 +163,7 @@ $table->temporary();
|
||||
|
||||
## 重新命名資料表
|
||||
|
||||
若您希望重新命名一個數據表,可以通過 `rename` 方法:
|
||||
若您希望重新命名一個數據表,可以透過 `rename` 方法:
|
||||
|
||||
```php
|
||||
Schema::rename($from, $to);
|
||||
@ -175,7 +175,7 @@ Schema::rename($from, $to);
|
||||
|
||||
## 刪除資料表
|
||||
|
||||
刪除一個已存在的資料表,可以通過 `drop` 或 `dropIfExists` 方法:
|
||||
刪除一個已存在的資料表,可以透過 `drop` 或 `dropIfExists` 方法:
|
||||
|
||||
```php
|
||||
Schema::drop('users');
|
||||
@ -185,7 +185,7 @@ Schema::dropIfExists('users');
|
||||
|
||||
## 檢查資料表或欄位是否存在
|
||||
|
||||
可以通過 `hasTable` 和 `hasColumn` 方法來檢查資料表或欄位是否存在:
|
||||
可以透過 `hasTable` 和 `hasColumn` 方法來檢查資料表或欄位是否存在:
|
||||
|
||||
```php
|
||||
if (Schema::hasTable('users')) {
|
||||
@ -199,7 +199,7 @@ if (Schema::hasColumn('name', 'email')) {
|
||||
|
||||
## 資料庫連線選項
|
||||
|
||||
如果在同時管理多個數據庫的情況下,不同的遷移會對應不同的資料庫連線,那麼此時我們可以在遷移檔案中通過重寫父類的 `$connection` 類屬性來定義不同的資料庫連線:
|
||||
如果在同時管理多個數據庫的情況下,不同的遷移會對應不同的資料庫連線,那麼此時我們可以在遷移檔案中透過重寫父類的 `$connection` 類屬性來定義不同的資料庫連線:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -347,7 +347,7 @@ Schema::table('users', function (Blueprint $table) {
|
||||
|
||||
### 重新命名欄位
|
||||
|
||||
可以通過 `renameColumn` 方法來重新命名欄位:
|
||||
可以透過 `renameColumn` 方法來重新命名欄位:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -362,7 +362,7 @@ Schema::table('users', function (Blueprint $table) {
|
||||
|
||||
### 刪除欄位
|
||||
|
||||
可以通過 `dropColumn` 方法來刪除欄位:
|
||||
可以透過 `dropColumn` 方法來刪除欄位:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -390,7 +390,7 @@ Schema::table('users', function (Blueprint $table) {
|
||||
### 建立索引
|
||||
|
||||
### 唯一索引
|
||||
通過 `unique` 方法來建立一個唯一索引:
|
||||
透過 `unique` 方法來建立一個唯一索引:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -435,7 +435,7 @@ $table->index(['account_id', 'created_at'], '');
|
||||
|
||||
### 重新命名索引
|
||||
|
||||
您可通過 `renameIndex` 方法重新命名一個索引的名稱:
|
||||
您可透過 `renameIndex` 方法重新命名一個索引的名稱:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -445,7 +445,7 @@ $table->renameIndex('from', 'to');
|
||||
|
||||
### 刪除索引
|
||||
|
||||
您可通過下面的方法來刪除索引,預設情況下遷移程式會自動將資料庫名稱、索引的欄位名及索引型別簡單地連線在一起作為名稱。舉例如下:
|
||||
您可透過下面的方法來刪除索引,預設情況下遷移程式會自動將資料庫名稱、索引的欄位名及索引型別簡單地連線在一起作為名稱。舉例如下:
|
||||
|
||||
| 命令 | 描述 |
|
||||
| ------------------------------------------------------ | ------------------------- |
|
||||
@ -454,7 +454,7 @@ $table->renameIndex('from', 'to');
|
||||
| $table->dropIndex('geo_state_index'); | 從 geo 表中刪除基本索引 |
|
||||
| $table->dropSpatialIndex('geo_location_spatialindex'); | 從 geo 表中刪除空間索引 |
|
||||
|
||||
您也可以通過傳遞欄位陣列到 `dropIndex` 方法,遷移程式會根據表名、欄位和鍵型別生成的索引名稱:
|
||||
您也可以透過傳遞欄位陣列到 `dropIndex` 方法,遷移程式會根據表名、欄位和鍵型別生成的索引名稱:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -466,7 +466,7 @@ Schema:table('users', function (Blueprint $table) {
|
||||
|
||||
### 外來鍵約束
|
||||
|
||||
我們還可以通過 `foreign`、`references`、`on` 方法建立資料庫層的外來鍵約束。比如我們讓 `posts` 表定義一個引用 `users` 表的 `id` 欄位的 `user_id` 欄位:
|
||||
我們還可以透過 `foreign`、`references`、`on` 方法建立資料庫層的外來鍵約束。比如我們讓 `posts` 表定義一個引用 `users` 表的 `id` 欄位的 `user_id` 欄位:
|
||||
|
||||
```php
|
||||
Schema::table('posts', function (Blueprint $table) {
|
||||
@ -484,7 +484,7 @@ $table->foreign('user_id')
|
||||
->onDelete('cascade');
|
||||
```
|
||||
|
||||
您可以通過 `dropForeign` 方法來刪除外來鍵。外來鍵約束採用的命名方式與索引相同,然後加上 `_foreign` 字尾:
|
||||
您可以透過 `dropForeign` 方法來刪除外來鍵。外來鍵約束採用的命名方式與索引相同,然後加上 `_foreign` 字尾:
|
||||
|
||||
```php
|
||||
$table->dropForeign('posts_user_id_foreign');
|
||||
|
@ -1,6 +1,6 @@
|
||||
# 模型快取
|
||||
|
||||
在高頻的業務場景下,我們可能會頻繁的查詢資料庫獲取業務資料,雖然有主鍵索引的加持,但也不可避免的對資料庫效能造成了極大的考驗。而對於這種 kv 的查詢方式,我們可以很方便的通過使用 `模型快取` 來減緩資料庫的壓力。本元件實現了 Model 資料自動快取的功能,且當刪除和修改模型資料時,自動刪除和修改對應的快取。執行累加、累減操作時,快取資料自動進行對應累加、累減變更。
|
||||
在高頻的業務場景下,我們可能會頻繁的查詢資料庫獲取業務資料,雖然有主鍵索引的加持,但也不可避免的對資料庫效能造成了極大的考驗。而對於這種 kv 的查詢方式,我們可以很方便的透過使用 `模型快取` 來減緩資料庫的壓力。本元件實現了 Model 資料自動快取的功能,且當刪除和修改模型資料時,自動刪除和修改對應的快取。執行累加、累減操作時,快取資料自動進行對應累加、累減變更。
|
||||
|
||||
> 模型快取暫時只支援 `Redis` 儲存驅動,其他儲存引擎歡迎社群提交對應的實現。
|
||||
|
||||
@ -104,7 +104,7 @@ class User extends Model implements CacheableInterface
|
||||
/** @var int|string $id */
|
||||
$model = User::findFromCache($id);
|
||||
|
||||
// 批量查詢快取,返回 Hyperf\Database\Model\Collection
|
||||
// 批次查詢快取,返回 Hyperf\Database\Model\Collection
|
||||
/** @var array $ids */
|
||||
$models = User::findManyFromCache($ids);
|
||||
|
||||
@ -129,11 +129,11 @@ $models = User::findManyFromCache($ids);
|
||||
```
|
||||
|
||||
另外一點需要注意的就是,快取的更新機制,框架內實現了對應的 `Hyperf\ModelCache\Listener\DeleteCacheListener` 監聽器,每當資料修改時,框架會主動刪除對應的快取資料。
|
||||
如果您不希望由框架來自動刪除對應的快取,可以通過主動覆寫 Model 的 `deleteCache` 方法,然後自行實現對應監聽即可。
|
||||
如果您不希望由框架來自動刪除對應的快取,可以透過主動覆寫 Model 的 `deleteCache` 方法,然後自行實現對應監聽即可。
|
||||
|
||||
### 批量修改或刪除
|
||||
### 批次修改或刪除
|
||||
|
||||
`Hyperf\ModelCache\Cacheable` 會自動接管 `Model::query` 方法,只需要使用者通過以下方式進行資料的刪除,就可以自動清理對應的快取資料。
|
||||
`Hyperf\ModelCache\Cacheable` 會自動接管 `Model::query` 方法,只需要使用者透過以下方式進行資料的刪除,就可以自動清理對應的快取資料。
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -169,7 +169,7 @@ class User extends Model implements CacheableInterface
|
||||
|
||||
### EagerLoad
|
||||
|
||||
當我們使用模型關係時,可以通過 `load` 解決 `N+1` 的問題,但仍然需要查一次資料庫。模型快取通過重寫了 `ModelBuilder`,可以讓使用者儘可能的從快取中拿到對應的模型。
|
||||
當我們使用模型關係時,可以透過 `load` 解決 `N+1` 的問題,但仍然需要查一次資料庫。模型快取透過重寫了 `ModelBuilder`,可以讓使用者儘可能的從快取中拿到對應的模型。
|
||||
|
||||
> 本功能不支援 `morphTo` 和不是隻有 `whereIn` 查詢的關係模型。
|
||||
|
||||
@ -185,7 +185,7 @@ return [
|
||||
];
|
||||
```
|
||||
|
||||
通過 `loadCache` 方法,載入對應的模型關係。
|
||||
透過 `loadCache` 方法,載入對應的模型關係。
|
||||
|
||||
```php
|
||||
$books = Book::findManyFromCache([1,2,3]);
|
||||
@ -223,4 +223,4 @@ foreach ($books as $book){
|
||||
|
||||
- Hyperf\ModelCache\Handler\RedisStringHandler
|
||||
|
||||
使用 `String` 儲存快取,因為是序列化的資料,所以支援所有資料型別,不足是無法有效處理 `Model::increment()`,當模型呼叫累加時,通過刪除快取,解決一致性的問題。
|
||||
使用 `String` 儲存快取,因為是序列化的資料,所以支援所有資料型別,不足是無法有效處理 `Model::increment()`,當模型呼叫累加時,透過刪除快取,解決一致性的問題。
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
## 建立模型
|
||||
|
||||
Hyperf 提供了建立模型的命令,您可以很方便的根據資料表建立對應模型。命令通過 `AST` 生成模型,所以當您增加了某些方法後,也可以使用指令碼方便的重置模型。
|
||||
Hyperf 提供了建立模型的命令,您可以很方便的根據資料表建立對應模型。命令透過 `AST` 生成模型,所以當您增加了某些方法後,也可以使用指令碼方便的重置模型。
|
||||
|
||||
```
|
||||
php bin/hyperf.php gen:model table_name
|
||||
@ -109,14 +109,14 @@ class User extends Model
|
||||
| table | string | 無 | 資料表名稱 |
|
||||
| primaryKey | string | id | 模型主鍵 |
|
||||
| keyType | string | int | 主鍵型別 |
|
||||
| fillable | array | [] | 允許被批量賦值的屬性 |
|
||||
| fillable | array | [] | 允許被批次賦值的屬性 |
|
||||
| casts | string | 無 | 資料格式化配置 |
|
||||
| timestamps | bool | true | 是否自動維護時間戳 |
|
||||
| incrementing | bool | true | 是否自增主鍵 |
|
||||
|
||||
### 資料表名稱
|
||||
|
||||
如果我們沒有指定模型對應的 table,它將使用類的複數形式「蛇形命名」來作為表名。因此,在這種情況下,Hyperf 將假設 User 模型儲存的是 users 資料表中的資料。你可以通過在模型上定義 table 屬性來指定自定義資料表:
|
||||
如果我們沒有指定模型對應的 table,它將使用類的複數形式「蛇形命名」來作為表名。因此,在這種情況下,Hyperf 將假設 User 模型儲存的是 users 資料表中的資料。你可以透過在模型上定義 table 屬性來指定自定義資料表:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -175,7 +175,7 @@ class User extends Model
|
||||
}
|
||||
```
|
||||
|
||||
如果您需要不希望保持 `datetime` 格式的儲存,或者希望對時間做進一步的處理,您可以通過在模型內重寫 `fromDateTime($value)` 方法實現。
|
||||
如果您需要不希望保持 `datetime` 格式的儲存,或者希望對時間做進一步的處理,您可以透過在模型內重寫 `fromDateTime($value)` 方法實現。
|
||||
|
||||
如果你需要自定義儲存時間戳的欄位名,可以在模型中設定 `CREATED_AT` 和 `UPDATED_AT` 常量的值來實現,其中一個為 `null`,則表明不希望 ORM 處理該欄位:
|
||||
|
||||
@ -372,7 +372,7 @@ $user->name = 'Hi Hyperf';
|
||||
$user->save();
|
||||
```
|
||||
|
||||
### 批量更新
|
||||
### 批次更新
|
||||
|
||||
也可以更新匹配查詢條件的多個模型。在這個示例中,所有的 `gender` 為 `1` 的使用者,修改 `gender_show` 為 男性:
|
||||
|
||||
@ -382,15 +382,15 @@ use App\Model\User;
|
||||
User::query()->where('gender', 1)->update(['gender_show' => '男性']);
|
||||
```
|
||||
|
||||
> 批量更新時, 更新的模型不會觸發 `saved` 和 `updated` 事件。因為在批量更新時,並沒有例項化模型。同時,也不會執行相應的 `casts`,例如資料庫中 `json` 格式,在 Model 類中 `casts` 欄位標記為 `array`,若是用批量更新,則插入時不會自動將 `array` 轉換為 `json` 字串格式。
|
||||
> 批次更新時, 更新的模型不會觸發 `saved` 和 `updated` 事件。因為在批次更新時,並沒有例項化模型。同時,也不會執行相應的 `casts`,例如資料庫中 `json` 格式,在 Model 類中 `casts` 欄位標記為 `array`,若是用批次更新,則插入時不會自動將 `array` 轉換為 `json` 字串格式。
|
||||
|
||||
### 批量賦值
|
||||
### 批次賦值
|
||||
|
||||
你也可以使用 `create` 方法來儲存新模型,此方法會返回模型例項。不過,在使用之前,你需要在模型上指定 `fillable` 或 `guarded` 屬性,因為所有的模型都預設不可進行批量賦值。
|
||||
你也可以使用 `create` 方法來儲存新模型,此方法會返回模型例項。不過,在使用之前,你需要在模型上指定 `fillable` 或 `guarded` 屬性,因為所有的模型都預設不可進行批次賦值。
|
||||
|
||||
當用戶通過 HTTP 請求傳入一個意外的引數,並且該引數更改了資料庫中你不需要更改的欄位時。比如:惡意使用者可能會通過 HTTP 請求傳入 `is_admin` 引數,然後將其傳給 `create` 方法,此操作能讓使用者將自己升級成管理員。
|
||||
當用戶透過 HTTP 請求傳入一個意外的引數,並且該引數更改了資料庫中你不需要更改的欄位時。比如:惡意使用者可能會透過 HTTP 請求傳入 `is_admin` 引數,然後將其傳給 `create` 方法,此操作能讓使用者將自己升級成管理員。
|
||||
|
||||
所以,在開始之前,你應該定義好模型上的哪些屬性是可以被批量賦值的。你可以通過模型上的 `$fillable` 屬性來實現。 例如:讓 `User` 模型的 `name` 屬性可以被批量賦值:
|
||||
所以,在開始之前,你應該定義好模型上的哪些屬性是可以被批次賦值的。你可以透過模型上的 `$fillable` 屬性來實現。 例如:讓 `User` 模型的 `name` 屬性可以被批次賦值:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -407,7 +407,7 @@ class User extends Model
|
||||
}
|
||||
```
|
||||
|
||||
一旦我們設定好了可以批量賦值的屬性,就可以通過 `create` 方法插入新資料到資料庫中了。 `create` 方法將返回儲存的模型例項:
|
||||
一旦我們設定好了可以批次賦值的屬性,就可以透過 `create` 方法插入新資料到資料庫中了。 `create` 方法將返回儲存的模型例項:
|
||||
|
||||
```php
|
||||
use App\Model\User;
|
||||
@ -423,7 +423,7 @@ $user->fill(['name' => 'Hyperf']);
|
||||
|
||||
### 保護屬性
|
||||
|
||||
`$fillable` 可以看作批量賦值的「白名單」, 你也可以使用 `$guarded` 屬性來實現。 `$guarded` 屬性包含的是不允許批量賦值的陣列。也就是說, `$guarded` 從功能上將更像是一個「黑名單」。注意:你只能使用 `$fillable` 或 `$guarded` 二者中的一個,不可同時使用。下面這個例子中,除了 `gender_show` 屬性,其他的屬性都可以批量賦值:
|
||||
`$fillable` 可以看作批次賦值的「白名單」, 你也可以使用 `$guarded` 屬性來實現。 `$guarded` 屬性包含的是不允許批次賦值的陣列。也就是說, `$guarded` 從功能上將更像是一個「黑名單」。注意:你只能使用 `$fillable` 或 `$guarded` 二者中的一個,不可同時使用。下面這個例子中,除了 `gender_show` 屬性,其他的屬性都可以批次賦值:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -444,29 +444,29 @@ class User extends Model
|
||||
|
||||
`firstOrCreate` / `firstOrNew`
|
||||
|
||||
這裡有兩個你可能用來批量賦值的方法: `firstOrCreate` 和 `firstOrNew`。
|
||||
這裡有兩個你可能用來批次賦值的方法: `firstOrCreate` 和 `firstOrNew`。
|
||||
|
||||
`firstOrCreate` 方法會通過給定的 列 / 值 來匹配資料庫中的資料。如果在資料庫中找不到對應的模型, 則會從第一個引數的屬性乃至第二個引數的屬性中建立一條記錄插入到資料庫。
|
||||
`firstOrCreate` 方法會透過給定的 列 / 值 來匹配資料庫中的資料。如果在資料庫中找不到對應的模型, 則會從第一個引數的屬性乃至第二個引數的屬性中建立一條記錄插入到資料庫。
|
||||
|
||||
`firstOrNew` 方法像 `firstOrCreate` 方法一樣嘗試通過給定的屬性查詢資料庫中的記錄。不同的是,如果 `firstOrNew` 方法找不到對應的模型,會返回一個新的模型例項。注意 `firstOrNew` 返回的模型例項尚未儲存到資料庫中,你需要手動呼叫 `save` 方法來儲存:
|
||||
`firstOrNew` 方法像 `firstOrCreate` 方法一樣嘗試透過給定的屬性查詢資料庫中的記錄。不同的是,如果 `firstOrNew` 方法找不到對應的模型,會返回一個新的模型例項。注意 `firstOrNew` 返回的模型例項尚未儲存到資料庫中,你需要手動呼叫 `save` 方法來儲存:
|
||||
|
||||
```php
|
||||
<?php
|
||||
use App\Model\User;
|
||||
|
||||
// 通過 name 來查詢使用者,不存在則建立...
|
||||
// 透過 name 來查詢使用者,不存在則建立...
|
||||
$user = User::firstOrCreate(['name' => 'Hyperf']);
|
||||
|
||||
// 通過 name 查詢使用者,不存在則使用 name 和 gender, age 屬性建立...
|
||||
// 透過 name 查詢使用者,不存在則使用 name 和 gender, age 屬性建立...
|
||||
$user = User::firstOrCreate(
|
||||
['name' => 'Hyperf'],
|
||||
['gender' => 1, 'age' => 20]
|
||||
);
|
||||
|
||||
// 通過 name 查詢使用者,不存在則建立一個例項...
|
||||
// 透過 name 查詢使用者,不存在則建立一個例項...
|
||||
$user = User::firstOrNew(['name' => 'Hyperf']);
|
||||
|
||||
// 通過 name 查詢使用者,不存在則使用 name 和 gender, age 屬性建立一個例項...
|
||||
// 透過 name 查詢使用者,不存在則使用 name 和 gender, age 屬性建立一個例項...
|
||||
$user = User::firstOrNew(
|
||||
['name' => 'Hyperf'],
|
||||
['gender' => 1, 'age' => 20]
|
||||
@ -485,9 +485,9 @@ $user = User::query()->find(1);
|
||||
$user->delete();
|
||||
```
|
||||
|
||||
### 通過查詢刪除模型
|
||||
### 透過查詢刪除模型
|
||||
|
||||
您可通過在查詢上呼叫 `delete` 方法來刪除模型資料,在這個例子中,我們將刪除所有 `gender` 為 `1` 的使用者。與批量更新一樣,批量刪除不會為刪除的模型啟動任何模型事件:
|
||||
您可透過在查詢上呼叫 `delete` 方法來刪除模型資料,在這個例子中,我們將刪除所有 `gender` 為 `1` 的使用者。與批次更新一樣,批次刪除不會為刪除的模型啟動任何模型事件:
|
||||
|
||||
```php
|
||||
use App\Model\User;
|
||||
@ -496,9 +496,9 @@ use App\Model\User;
|
||||
User::query()->where('gender', 1)->delete();
|
||||
```
|
||||
|
||||
### 通過主鍵直接刪除資料
|
||||
### 透過主鍵直接刪除資料
|
||||
|
||||
在上面的例子中,在呼叫 `delete` 之前需要先去資料庫中查詢對應的模型。事實上,如果你知道了模型的主鍵,您可以直接通過 `destroy` 靜態方法來刪除模型資料,而不用先去資料庫中查詢。 `destroy` 方法除了接受單個主鍵作為引數之外,還接受多個主鍵,或者使用陣列,集合來儲存多個主鍵:
|
||||
在上面的例子中,在呼叫 `delete` 之前需要先去資料庫中查詢對應的模型。事實上,如果你知道了模型的主鍵,您可以直接透過 `destroy` 靜態方法來刪除模型資料,而不用先去資料庫中查詢。 `destroy` 方法除了接受單個主鍵作為引數之外,還接受多個主鍵,或者使用陣列,集合來儲存多個主鍵:
|
||||
|
||||
```php
|
||||
use App\Model\User;
|
||||
@ -565,4 +565,4 @@ class SupportMySQLBitListener implements ListenerInterface
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
```
|
||||
|
@ -40,7 +40,7 @@ $user = App\User::find(1);
|
||||
$firstName = $user->first_name;
|
||||
```
|
||||
|
||||
當然,你也可以通過已有的屬性值,使用訪問器返回新的計算值:
|
||||
當然,你也可以透過已有的屬性值,使用訪問器返回新的計算值:
|
||||
|
||||
```php
|
||||
namespace App;
|
||||
@ -99,7 +99,7 @@ $user->first_name = 'Sally';
|
||||
|
||||
## 日期轉化器
|
||||
|
||||
預設情況下,模型會將 `created_at` 和 `updated_at` 欄位轉換為 `Carbon` 例項,它繼承了 `PHP` 原生的 `DateTime` 類並提供了各種有用的方法。你可以通過設定模型的 `$dates` 屬性來新增其他日期屬性:
|
||||
預設情況下,模型會將 `created_at` 和 `updated_at` 欄位轉換為 `Carbon` 例項,它繼承了 `PHP` 原生的 `DateTime` 類並提供了各種有用的方法。你可以透過設定模型的 `$dates` 屬性來新增其他日期屬性:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -122,7 +122,7 @@ class User extends Model
|
||||
|
||||
```
|
||||
|
||||
> Tip: 你可以通過將模型的公有屬性 $timestamps 值設定為 false 來禁用預設的 created_at 和 updated_at 時間戳。
|
||||
> Tip: 你可以透過將模型的公有屬性 $timestamps 值設定為 false 來禁用預設的 created_at 和 updated_at 時間戳。
|
||||
|
||||
當某個欄位是日期格式時,你可以將值設定為一個 `UNIX` 時間戳,日期時間 `(Y-m-d)` 字串,或者 `DateTime` / `Carbon` 例項。日期值會被正確格式化並儲存到你的資料庫中:
|
||||
|
||||
@ -195,7 +195,7 @@ if ($user->is_admin) {
|
||||
|
||||
### 自定義型別轉換
|
||||
|
||||
模型內建了多種常用的型別轉換。但是,使用者偶爾會需要將資料轉換成自定義型別。現在,該需求可以通過定義一個實現 `CastsAttributes` 介面的類來完成
|
||||
模型內建了多種常用的型別轉換。但是,使用者偶爾會需要將資料轉換成自定義型別。現在,該需求可以透過定義一個實現 `CastsAttributes` 介面的類來完成
|
||||
|
||||
實現了該介面的類必須事先定義一個 `get` 和 `set` 方法。 `get` 方法負責將從資料庫中獲取的原始資料轉換成對應的型別,而 `set` 方法則是將資料轉換成對應的資料庫型別以便存入資料庫中。舉個例子,下面我們將內建的 `json` 型別轉換以自定義型別轉換的形式重新實現一遍:
|
||||
|
||||
@ -321,7 +321,7 @@ var_dump($user->getAttributes());
|
||||
$user->address->lineOne = 'Updated Address Value';
|
||||
$user->address->lineTwo = '#20000';
|
||||
|
||||
// 直接修改 address 的欄位後,是無法立馬再 attributes 中生效的,但可以直接通過 $user->address 拿到修改後的資料。
|
||||
// 直接修改 address 的欄位後,是無法立馬再 attributes 中生效的,但可以直接透過 $user->address 拿到修改後的資料。
|
||||
var_dump($user->getAttributes());
|
||||
//[
|
||||
// 'address_line_one' => 'Address Value',
|
||||
@ -337,7 +337,7 @@ var_dump($user->getAttributes());
|
||||
//];
|
||||
```
|
||||
|
||||
如果修改 `address` 後,不想要儲存,也不想通過 `address->lineOne` 獲取 `address_line_one` 的資料,還可以使用以下 方法
|
||||
如果修改 `address` 後,不想要儲存,也不想透過 `address->lineOne` 獲取 `address_line_one` 的資料,還可以使用以下 方法
|
||||
|
||||
```php
|
||||
$user = App\User::find(1);
|
||||
@ -540,7 +540,7 @@ $users = User::select([
|
||||
])->get();
|
||||
```
|
||||
|
||||
在該查詢獲取到的結果集中,`last_posted_at` 屬性將會是一個字串。假如我們在執行查詢時進行 `date` 型別轉換將更方便。你可以通過使用 `withCasts` 方法來完成上述操作:
|
||||
在該查詢獲取到的結果集中,`last_posted_at` 屬性將會是一個字串。假如我們在執行查詢時進行 `date` 型別轉換將更方便。你可以透過使用 `withCasts` 方法來完成上述操作:
|
||||
|
||||
```php
|
||||
$users = User::select([
|
||||
|
@ -1,10 +1,10 @@
|
||||
# 查詢分頁
|
||||
|
||||
在使用 [hyperf/database](https://github.com/hyperf/database) 來查詢資料時,可以很方便的通過與 [hyperf/paginator](https://github.com/hyperf/paginator) 元件配合便捷地對查詢結果進行分頁。
|
||||
在使用 [hyperf/database](https://github.com/hyperf/database) 來查詢資料時,可以很方便的透過與 [hyperf/paginator](https://github.com/hyperf/paginator) 元件配合便捷地對查詢結果進行分頁。
|
||||
|
||||
# 使用方法
|
||||
|
||||
在您通過 [查詢構造器](zh-tw/db/querybuilder.md) 或 [模型](zh-tw/db/model.md) 查詢資料時,可以通過 `paginate` 方法來處理分頁,該方法會自動根據使用者正在檢視的頁面來設定限制和偏移量,預設情況下,通過當前 HTTP 請求所帶的 `page` 引數的值來檢測當前的頁數:
|
||||
在您透過 [查詢構造器](zh-tw/db/querybuilder.md) 或 [模型](zh-tw/db/model.md) 查詢資料時,可以透過 `paginate` 方法來處理分頁,該方法會自動根據使用者正在檢視的頁面來設定限制和偏移量,預設情況下,通過當前 HTTP 請求所帶的 `page` 引數的值來檢測當前的頁數:
|
||||
|
||||
> 由於 Hyperf 當前並不支援檢視,所以分頁元件尚未支援對檢視的渲染,直接返回分頁結果預設會以 application/json 格式輸出。
|
||||
|
||||
@ -18,7 +18,7 @@ return Db::table('users')->paginate(10);
|
||||
|
||||
## 模型分頁
|
||||
|
||||
您可以直接通過靜態方法呼叫 `paginate` 方法來進行分頁:
|
||||
您可以直接透過靜態方法呼叫 `paginate` 方法來進行分頁:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
@ -19,7 +19,7 @@ $users = Db::table('user')->get();
|
||||
$users = Db::table('user')->select('name', 'gender as user_gender')->get();
|
||||
```
|
||||
|
||||
`Db::select()` 方法會返回一個 array,而 `get` 方法會返回 `Hyperf\Utils\Collection`。其中元素是 `stdClass`,所以可以通過以下程式碼返回各個元素的資料
|
||||
`Db::select()` 方法會返回一個 array,而 `get` 方法會返回 `Hyperf\Utils\Collection`。其中元素是 `stdClass`,所以可以透過以下程式碼返回各個元素的資料
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -31,7 +31,7 @@ foreach ($users as $user) {
|
||||
|
||||
### 將結果轉為陣列格式
|
||||
|
||||
在某些場景下,您可能會希望查詢出來的結果內採用 `陣列(Array)` 而不是 `stdClass` 物件結構時,而 `Eloquent` 又去除了通過配置的形式配置預設的 `FetchMode`,那麼此時可以通過監聽器來監聽 `Hyperf\Database\Events\StatementPrepared` 事件來變更該配置:
|
||||
在某些場景下,您可能會希望查詢出來的結果內採用 `陣列(Array)` 而不是 `stdClass` 物件結構時,而 `Eloquent` 又去除了透過配置的形式配置預設的 `FetchMode`,那麼此時可以透過監聽器來監聽 `Hyperf\Database\Events\StatementPrepared` 事件來變更該配置:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -132,7 +132,7 @@ Db::table('user')->orderBy('id')->chunk(100, function ($users) {
|
||||
});
|
||||
```
|
||||
|
||||
你可以通過在 閉包 中返回 `false` 來終止繼續獲取分塊結果:
|
||||
你可以透過在 閉包 中返回 `false` 來終止繼續獲取分塊結果:
|
||||
|
||||
```php
|
||||
use Hyperf\DbConnection\Db;
|
||||
@ -171,7 +171,7 @@ $count = Db::table('user')->count();
|
||||
|
||||
#### 判斷記錄是否存在
|
||||
|
||||
除了通過 `count` 方法可以確定查詢條件的結果是否存在之外,還可以使用 `exists` 和 `doesntExist` 方法:
|
||||
除了透過 `count` 方法可以確定查詢條件的結果是否存在之外,還可以使用 `exists` 和 `doesntExist` 方法:
|
||||
|
||||
```php
|
||||
return Db::table('orders')->where('finalized', 1)->exists();
|
||||
@ -215,7 +215,7 @@ $res = Db::table('user')->select('gender', Db::raw('COUNT(0) AS `count`'))->grou
|
||||
|
||||
### 強制索引
|
||||
|
||||
資料庫出現的慢查問題, 90% 以上是索引不對, 其中有部分查詢是因為資料庫伺服器的 `查詢優化器` 沒有使用最佳索引, 這時候就需要使用強制索引:
|
||||
資料庫出現的慢查問題, 90% 以上是索引不對, 其中有部分查詢是因為資料庫伺服器的 `查詢最佳化器` 沒有使用最佳索引, 這時候就需要使用強制索引:
|
||||
|
||||
```php
|
||||
Db::table(Db::raw("{$table} FORCE INDEX({$index})"));
|
||||
@ -453,7 +453,7 @@ Db::table('users')->where('name', '=', 'John')
|
||||
->get();
|
||||
```
|
||||
|
||||
你可以看到,通過一個 `Closure` 寫入 `where` 方法構建一個查詢構造器 來約束一個分組。這個 `Closure` 接收一個查詢例項,你可以使用這個例項來設定應該包含的約束。上面的例子將生成以下 SQL:
|
||||
你可以看到,透過一個 `Closure` 寫入 `where` 方法構建一個查詢構造器 來約束一個分組。這個 `Closure` 接收一個查詢例項,你可以使用這個例項來設定應該包含的約束。上面的例子將生成以下 SQL:
|
||||
|
||||
```sql
|
||||
select * from users where name = 'John' and (votes > 100 or title = 'Admin')
|
||||
@ -521,7 +521,7 @@ $users = Db::table('users')
|
||||
|
||||
### orderBy
|
||||
|
||||
`orderBy` 方法允許你通過給定欄位對結果集進行排序。 `orderBy` 的第一個引數應該是你希望排序的欄位,第二個引數控制排序的方向,可以是 `asc` 或 `desc`
|
||||
`orderBy` 方法允許你透過給定欄位對結果集進行排序。 `orderBy` 的第一個引數應該是你希望排序的欄位,第二個引數控制排序的方向,可以是 `asc` 或 `desc`
|
||||
|
||||
```php
|
||||
$users = Db::table('users')
|
||||
@ -531,7 +531,7 @@ $users = Db::table('users')
|
||||
|
||||
### latest / oldest
|
||||
|
||||
`latest` 和 `oldest` 方法可以使你輕鬆地通過日期排序。它預設使用 `created_at` 列作為排序依據。當然,你也可以傳遞自定義的列名:
|
||||
`latest` 和 `oldest` 方法可以使你輕鬆地透過日期排序。它預設使用 `created_at` 列作為排序依據。當然,你也可以傳遞自定義的列名:
|
||||
|
||||
```php
|
||||
$user = Db::table('users')->latest()->first();
|
||||
@ -583,7 +583,7 @@ $users = Db::table('users')->offset(10)->limit(5)->get();
|
||||
|
||||
## 條件語句
|
||||
|
||||
有時候你可能想要子句只適用於某個情況為真是才執行查詢。例如你可能只想給定值在請求中存在的情況下才應用 `where` 語句。 你可以通過使用 `when` 方法:
|
||||
有時候你可能想要子句只適用於某個情況為真是才執行查詢。例如你可能只想給定值在請求中存在的情況下才應用 `where` 語句。 你可以透過使用 `when` 方法:
|
||||
|
||||
```php
|
||||
$role = $request->input('role');
|
||||
@ -642,7 +642,7 @@ $id = Db::table('users')->insertGetId(
|
||||
|
||||
## 更新
|
||||
|
||||
當然, 除了插入記錄到資料庫中,查詢構造器也可以通過 `update` 方法更新已有的記錄。 `update` 方法和 `insert` 方法一樣,接受包含要更新的欄位及值的陣列。你可以通過 `where` 子句對 `update` 查詢進行約束:
|
||||
當然, 除了插入記錄到資料庫中,查詢構造器也可以透過 `update` 方法更新已有的記錄。 `update` 方法和 `insert` 方法一樣,接受包含要更新的欄位及值的陣列。你可以透過 `where` 子句對 `update` 查詢進行約束:
|
||||
|
||||
```php
|
||||
Db::table('users')->where('id', 1)->update(['votes' => 1]);
|
||||
|
@ -60,7 +60,7 @@ class User extends Model
|
||||
|
||||
記住一點,`Hyperf` 將會自動確定 `Book` 模型的外來鍵屬性。按照約定,`Hyperf` 將會使用所屬模型名稱的 『snake case』形式,再加上 `_id` 字尾作為外來鍵欄位。因此,在上面這個例子中,`Hyperf` 將假定 `User` 對應到 `Book` 模型上的外來鍵就是 `user_id`。
|
||||
|
||||
一旦關係被定義好以後,就可以通過訪問 `User` 模型的 `books` 屬性來獲取評論的集合。記住,由於 Hyperf 提供了『動態屬性』 ,所以我們可以像訪問模型的屬性一樣訪問關聯方法:
|
||||
一旦關係被定義好以後,就可以透過訪問 `User` 模型的 `books` 屬性來獲取評論的集合。記住,由於 Hyperf 提供了『動態屬性』 ,所以我們可以像訪問模型的屬性一樣訪問關聯方法:
|
||||
|
||||
```php
|
||||
$books = User::query()->find(1)->books;
|
||||
@ -78,7 +78,7 @@ $book = User::query()->find(1)->books()->where('title', '一個月精通Hyperf
|
||||
|
||||
### 一對多(反向)
|
||||
|
||||
現在,我們已經能獲得一個作者的所有作品,接著再定義一個通過書獲得其作者的關聯關係。這個關聯是 `hasMany` 關聯的反向關聯,需要在子級模型中使用 `belongsTo` 方法定義它:
|
||||
現在,我們已經能獲得一個作者的所有作品,接著再定義一個透過書獲得其作者的關聯關係。這個關聯是 `hasMany` 關聯的反向關聯,需要在子級模型中使用 `belongsTo` 方法定義它:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -98,7 +98,7 @@ class Book extends Model
|
||||
}
|
||||
```
|
||||
|
||||
這個關係定義好以後,我們就可以通過訪問 `Book` 模型的 author 這個『動態屬性』來獲取關聯的 `User` 模型了:
|
||||
這個關係定義好以後,我們就可以透過訪問 `Book` 模型的 author 這個『動態屬性』來獲取關聯的 `User` 模型了:
|
||||
|
||||
```php
|
||||
$book = Book::find(1);
|
||||
@ -110,7 +110,7 @@ echo $book->author->name;
|
||||
|
||||
多對多關聯比 `hasOne` 和 `hasMany` 關聯稍微複雜些。舉個例子,一個使用者可以擁有很多種角色,同時這些角色也被其他使用者共享。例如,許多使用者可能都有 「管理員」 這個角色。要定義這種關聯,需要三個資料庫表: `users`,`roles` 和 `role_user`。`role_user` 表的命名是由關聯的兩個模型按照字母順序來的,並且包含了 `user_id` 和 `role_id` 欄位。
|
||||
|
||||
多對多關聯通過呼叫 `belongsToMany` 這個內部方法返回的結果來定義,例如,我們在 `User` 模型中定義 `roles` 方法:
|
||||
多對多關聯透過呼叫 `belongsToMany` 這個內部方法返回的結果來定義,例如,我們在 `User` 模型中定義 `roles` 方法:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -128,7 +128,7 @@ class User extends Model
|
||||
}
|
||||
```
|
||||
|
||||
一旦關聯關係被定義後,你可以通過 `roles` 動態屬性獲取使用者角色:
|
||||
一旦關聯關係被定義後,你可以透過 `roles` 動態屬性獲取使用者角色:
|
||||
|
||||
```php
|
||||
$user = User::query()->find(1);
|
||||
@ -150,7 +150,7 @@ $roles = User::find(1)->roles()->orderBy('name')->get();
|
||||
return $this->belongsToMany(Role::class, 'role_user');
|
||||
```
|
||||
|
||||
除了自定義連線表的表名,你還可以通過傳遞額外的引數到 `belongsToMany` 方法來定義該表中欄位的鍵名。第三個引數是定義此關聯的模型在連線表裡的外來鍵名,第四個引數是另一個模型在連線表裡的外來鍵名:
|
||||
除了自定義連線表的表名,你還可以透過傳遞額外的引數到 `belongsToMany` 方法來定義該表中欄位的鍵名。第三個引數是定義此關聯的模型在連線表裡的外來鍵名,第四個引數是另一個模型在連線表裡的外來鍵名:
|
||||
|
||||
```php
|
||||
return $this->belongsToMany(Role::class, 'role_user', 'user_id', 'role_id');
|
||||
@ -202,7 +202,7 @@ foreach ($users->flatMap->podcasts as $podcast) {
|
||||
}
|
||||
```
|
||||
|
||||
#### 通過中間表過濾關係
|
||||
#### 透過中間表過濾關係
|
||||
|
||||
在定義關係時,你還可以使用 `wherePivot` 和 `wherePivotIn` 方法來過濾 `belongsToMany` 返回的結果:
|
||||
|
||||
@ -326,7 +326,7 @@ class User extends Model
|
||||
|
||||
#### 獲取關聯
|
||||
|
||||
按照上述定義模型後,我們就可以通過模型關係獲取對應的模型。
|
||||
按照上述定義模型後,我們就可以透過模型關係獲取對應的模型。
|
||||
|
||||
比如,我們獲取某使用者的圖片。
|
||||
|
||||
|
@ -44,7 +44,7 @@ composer require hyperf/resource-grpc
|
||||
php bin/hyperf.php gen:resource User --grpc
|
||||
```
|
||||
|
||||
gRPC 資源需要設定 `message` 類. 通過重寫該資源類的 `expect()` 方法來實現.
|
||||
gRPC 資源需要設定 `message` 類. 透過重寫該資源類的 `expect()` 方法來實現.
|
||||
|
||||
gRPC 服務返回時, 必須呼叫 `toMessage()`. 該方法會返回一個例項化的 `message` 類.
|
||||
|
||||
@ -73,7 +73,7 @@ class HiReplyResource extends GrpcResource
|
||||
|
||||
```
|
||||
|
||||
預設生成的資源集合, 可通過繼承 `Hyperf\ResourceGrpc\GrpcResource` 介面來使其支援 gRPC 返回.
|
||||
預設生成的資源集合, 可透過繼承 `Hyperf\ResourceGrpc\GrpcResource` 介面來使其支援 gRPC 返回.
|
||||
|
||||
## 概念綜述
|
||||
|
||||
@ -941,4 +941,4 @@ class IndexController extends AbstractController
|
||||
|
||||
```
|
||||
|
||||
如你想設定響應頭資訊, 狀態碼等, 通過呼叫 `toResponse()` 方法獲取到響應物件進行設定.
|
||||
如你想設定響應頭資訊, 狀態碼等, 透過呼叫 `toResponse()` 方法獲取到響應物件進行設定.
|
||||
|
@ -12,7 +12,7 @@ composer require hyperf/devtool
|
||||
php bin/hyperf.php
|
||||
```
|
||||
|
||||
通過執行上面的命令可獲得 Command 所支援的所有命令,其中返回結果 `gen` 系列命令和 `vendor:publish` 命令主要為 `devtool` 元件提供支援
|
||||
透過執行上面的命令可獲得 Command 所支援的所有命令,其中返回結果 `gen` 系列命令和 `vendor:publish` 命令主要為 `devtool` 元件提供支援
|
||||
|
||||
```bash
|
||||
gen
|
||||
|
@ -9,7 +9,7 @@ Hyperf 預設採用 [hyperf/di](https://github.com/hyperf/di) 作為框架的依
|
||||
|
||||
## 安裝
|
||||
|
||||
該元件預設存在 [hyperf-skeleton](https://github.com/hyperf/hyperf-skeleton) 專案中並作為主要元件存在,如希望在其它框架內使用該元件可通過下面的命令安裝。
|
||||
該元件預設存在 [hyperf-skeleton](https://github.com/hyperf/hyperf-skeleton) 專案中並作為主要元件存在,如希望在其它框架內使用該元件可透過下面的命令安裝。
|
||||
|
||||
```bash
|
||||
composer require hyperf/di
|
||||
@ -19,7 +19,7 @@ composer require hyperf/di
|
||||
|
||||
### 簡單物件注入
|
||||
|
||||
通常來說,類的關係及注入是無需顯性定義的,這一切 Hyperf 都會默默的為您完成,我們通過一些程式碼示例來說明一下相關的用法。
|
||||
通常來說,類的關係及注入是無需顯性定義的,這一切 Hyperf 都會默默的為您完成,我們透過一些程式碼示例來說明一下相關的用法。
|
||||
假設我們需要在 `IndexController` 內呼叫 `UserService` 類的 `getInfoById(int $id)` 方法。
|
||||
|
||||
```php
|
||||
@ -36,7 +36,7 @@ class UserService
|
||||
}
|
||||
```
|
||||
|
||||
#### 通過構造方法注入
|
||||
#### 透過構造方法注入
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -48,7 +48,7 @@ class IndexController
|
||||
{
|
||||
private UserService $userService;
|
||||
|
||||
// 通過在建構函式的引數上宣告引數型別完成自動注入
|
||||
// 透過在建構函式的引數上宣告引數型別完成自動注入
|
||||
public function __construct(UserService $userService)
|
||||
{
|
||||
$this->userService = $userService;
|
||||
@ -65,7 +65,7 @@ class IndexController
|
||||
|
||||
> 注意使用建構函式注入時,呼叫方也就是 `IndexController` 必須是由 DI 建立的物件才能完成自動注入,而 Controller 預設是由 DI 建立的,所以可以直接使用建構函式注入
|
||||
|
||||
當您希望定義一個可選的依賴項時,可以通過給引數定義為 `nullable` 或將引數的預設值定義為 `null`,即表示該引數如果在 DI 容器中沒有找到或無法建立對應的物件時,不丟擲異常而是直接使用 `null` 來注入。*(該功能僅在
|
||||
當您希望定義一個可選的依賴項時,可以透過給引數定義為 `nullable` 或將引數的預設值定義為 `null`,即表示該引數如果在 DI 容器中沒有找到或無法建立對應的物件時,不丟擲異常而是直接使用 `null` 來注入。*(該功能僅在
|
||||
1.1.0 或更高版本可用)*
|
||||
|
||||
```php
|
||||
@ -78,7 +78,7 @@ class IndexController
|
||||
{
|
||||
private ?UserService $userService;
|
||||
|
||||
// 通過設定引數為 nullable,表明該引數為一個可選引數
|
||||
// 透過設定引數為 nullable,表明該引數為一個可選引數
|
||||
public function __construct(?UserService $userService)
|
||||
{
|
||||
$this->userService = $userService;
|
||||
@ -96,7 +96,7 @@ class IndexController
|
||||
}
|
||||
```
|
||||
|
||||
#### 通過 `#[Inject]` 註解注入
|
||||
#### 透過 `#[Inject]` 註解注入
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -108,7 +108,7 @@ use Hyperf\Di\Annotation\Inject;
|
||||
class IndexController
|
||||
{
|
||||
/**
|
||||
* 通過 `#[Inject]` 註解注入由 `@var` 註解宣告的屬性型別物件
|
||||
* 透過 `#[Inject]` 註解注入由 `@var` 註解宣告的屬性型別物件
|
||||
*
|
||||
* @var UserService
|
||||
*/
|
||||
@ -124,7 +124,7 @@ class IndexController
|
||||
}
|
||||
```
|
||||
|
||||
> 通過 `#[Inject]` 註解注入可作用於 DI 建立的(單例)物件,也可作用於通過 `new` 關鍵詞建立的物件;
|
||||
> 透過 `#[Inject]` 註解注入可作用於 DI 建立的(單例)物件,也可作用於透過 `new` 關鍵詞建立的物件;
|
||||
|
||||
> 使用 `#[Inject]` 註解時需 `use Hyperf\Di\Annotation\Inject;` 名稱空間;
|
||||
|
||||
@ -143,7 +143,7 @@ use Hyperf\Di\Annotation\Inject;
|
||||
class IndexController
|
||||
{
|
||||
/**
|
||||
* 通過 `#[Inject]` 註解注入由 `@var` 註解宣告的屬性型別物件
|
||||
* 透過 `#[Inject]` 註解注入由 `@var` 註解宣告的屬性型別物件
|
||||
* 當 UserService 不存在於 DI 容器內或不可建立時,則注入 null
|
||||
*
|
||||
* @var UserService
|
||||
@ -166,7 +166,7 @@ class IndexController
|
||||
### 抽象物件注入
|
||||
|
||||
基於上面的例子,從合理的角度上來說,Controller 面向的不應該直接是一個 `UserService` 類,可能更多的是一個 `UserServiceInterface`
|
||||
的介面類,此時我們可以通過 `config/autoload/dependencies.php` 來繫結物件關係達到目的,我們還是通過程式碼來解釋一下。
|
||||
的介面類,此時我們可以透過 `config/autoload/dependencies.php` 來繫結物件關係達到目的,我們還是透過程式碼來解釋一下。
|
||||
|
||||
定義一個介面類:
|
||||
|
||||
@ -205,7 +205,7 @@ return [
|
||||
];
|
||||
```
|
||||
|
||||
這樣配置後就可以直接通過 `UserServiceInterface` 來注入 `UserService` 物件了,我們僅通過註解注入的方式來舉例,建構函式注入也是一樣的:
|
||||
這樣配置後就可以直接透過 `UserServiceInterface` 來注入 `UserService` 物件了,我們僅透過註解注入的方式來舉例,建構函式注入也是一樣的:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -292,7 +292,7 @@ return [
|
||||
|
||||
這樣在注入 `UserServiceInterface` 的時候容器就會交由 `UserServiceFactory` 來建立物件了。
|
||||
|
||||
> 當然在該場景中可以通過 `@Value` 註解來更便捷的注入配置而無需構建工廠類,此僅為舉例
|
||||
> 當然在該場景中可以透過 `@Value` 註解來更便捷的注入配置而無需構建工廠類,此僅為舉例
|
||||
|
||||
### 懶載入
|
||||
|
||||
@ -302,9 +302,9 @@ Hyperf 的長生命週期依賴注入在專案啟動時完成。這意味著長
|
||||
|
||||
* 建構函式中要避免迴圈依賴(比較典型的例子為 `Listener` 和 `EventDispatcherInterface`),不然也會啟動失敗。
|
||||
|
||||
目前解決方案是:只在例項中注入 `Psr\Container\ContainerInterface` ,而其他的元件在非建構函式執行時通過 `container` 獲取。但 PSR-11 中指出:
|
||||
目前解決方案是:只在例項中注入 `Psr\Container\ContainerInterface` ,而其他的元件在非建構函式執行時透過 `container` 獲取。但 PSR-11 中指出:
|
||||
|
||||
> 「使用者不應該將容器作為引數傳入物件然後在物件中通過容器獲得物件的依賴。這樣是把容器當作服務定位器來使用,而服務定位器是一種反模式」
|
||||
> 「使用者不應該將容器作為引數傳入物件然後在物件中透過容器獲得物件的依賴。這樣是把容器當作服務定位器來使用,而服務定位器是一種反模式」
|
||||
|
||||
也就是說這樣的做法雖然有效,但是從設計模式角度來說並不推薦。
|
||||
|
||||
@ -337,7 +337,7 @@ class Foo{
|
||||
}
|
||||
````
|
||||
|
||||
您還可以通過註解 `#[Inject(lazy: true)]` 注入懶載入代理。通過註解實現懶載入不用建立配置檔案。
|
||||
您還可以透過註解 `#[Inject(lazy: true)]` 注入懶載入代理。透過註解實現懶載入不用建立配置檔案。
|
||||
|
||||
```php
|
||||
use Hyperf\Di\Annotation\Inject;
|
||||
@ -374,20 +374,20 @@ unset($proxy->someProperty);
|
||||
|
||||
## 短生命週期物件
|
||||
|
||||
通過 `new` 關鍵詞建立的物件毫無疑問的短生命週期的,那麼如果希望建立一個短生命週期的物件但又希望使用 `建構函式依賴自動注入功能`
|
||||
呢?這時我們可以通過 `make(string $name, array $parameters = [])` 函式來建立 `$name` 對應的的例項,程式碼示例如下:
|
||||
透過 `new` 關鍵詞建立的物件毫無疑問的短生命週期的,那麼如果希望建立一個短生命週期的物件但又希望使用 `建構函式依賴自動注入功能`
|
||||
呢?這時我們可以透過 `make(string $name, array $parameters = [])` 函式來建立 `$name` 對應的的例項,程式碼示例如下:
|
||||
|
||||
```php
|
||||
$userService = make(UserService::class, ['enableCache' => true]);
|
||||
```
|
||||
|
||||
> 注意僅 `$name` 對應的物件為短生命週期物件,該物件的所有依賴都是通過 `get()` 方法獲取的,即為長生命週期的物件,可理解為該物件是一個淺拷貝的物件
|
||||
> 注意僅 `$name` 對應的物件為短生命週期物件,該物件的所有依賴都是透過 `get()` 方法獲取的,即為長生命週期的物件,可理解為該物件是一個淺複製的物件
|
||||
|
||||
## 獲取容器物件
|
||||
|
||||
有些時候我們可能希望去實現一些更動態的需求時,會希望可以直接獲取到 `容器(Container)` 物件,在絕大部分情況下,框架的入口類(比如命令類、控制器、RPC 服務提供者等)都是由 `容器(Container)`
|
||||
建立並維護的,也就意味著您所寫的絕大部分業務程式碼都是在 `容器(Container)` 的管理作用之下的,也就意味著在絕大部分情況下您都可以通過在 `建構函式(Constructor)` 宣告或通過 `#[Inject]`
|
||||
註解注入 `Psr\Container\ContainerInterface` 介面類都能夠獲得 `Hyperf\Di\Container` 容器物件,我們通過程式碼來演示一下:
|
||||
建立並維護的,也就意味著您所寫的絕大部分業務程式碼都是在 `容器(Container)` 的管理作用之下的,也就意味著在絕大部分情況下您都可以透過在 `建構函式(Constructor)` 宣告或透過 `#[Inject]`
|
||||
註解注入 `Psr\Container\ContainerInterface` 介面類都能夠獲得 `Hyperf\Di\Container` 容器物件,我們透過程式碼來演示一下:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -400,7 +400,7 @@ class IndexController
|
||||
{
|
||||
private ContainerInterface $container;
|
||||
|
||||
// 通過在建構函式的引數上宣告引數型別完成自動注入
|
||||
// 透過在建構函式的引數上宣告引數型別完成自動注入
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
@ -409,7 +409,7 @@ class IndexController
|
||||
```
|
||||
|
||||
在某些更極端動態的情況下,或者非 `容器(Container)` 的管理作用之下時,想要獲取到 `容器(Container)`
|
||||
物件還可以通過 `\Hyperf\Utils\ApplicationContext::getContaienr()` 方法來獲得 `容器(Container)` 物件。
|
||||
物件還可以透過 `\Hyperf\Utils\ApplicationContext::getContaienr()` 方法來獲得 `容器(Container)` 物件。
|
||||
|
||||
```php
|
||||
$container = \Hyperf\Utils\ApplicationContext::getContainer();
|
||||
|
@ -1,6 +1,6 @@
|
||||
# 捐獻及贊助
|
||||
|
||||
Hyperf 是採用 MIT 許可的開源專案,使用完全免費。但是隨著專案規模的增長,也需要有相應的資金支援才能持續專案的維護的開發。您可以通過下列的方法來贊助 Hyperf 的開發。
|
||||
Hyperf 是採用 MIT 許可的開源專案,使用完全免費。但是隨著專案規模的增長,也需要有相應的資金支援才能持續專案的維護的開發。您可以透過下列的方法來贊助 Hyperf 的開發。
|
||||
|
||||
## 贊助 Hyperf 的研發
|
||||
|
||||
@ -8,7 +8,7 @@ Hyperf 是採用 MIT 許可的開源專案,使用完全免費。但是隨著
|
||||
|
||||
如果您是個人開發者並且享受 Hyperf 帶來的高開發效率,可以用一次性贊助來表示您的謝意 —— 就好像偶爾給我們買杯咖啡 :)
|
||||
|
||||
我們通過以下方式接受贊助:
|
||||
我們透過以下方式接受贊助:
|
||||
|
||||
![alipay](imgs/alipay.jpg ':size=375x562')
|
||||
![wechat](imgs/wechatpay.jpg ':size=375x562')
|
||||
|
@ -3,7 +3,7 @@
|
||||
## 前言
|
||||
|
||||
事件模式必須基於 [PSR-14](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-14-event-dispatcher.md) 去實現。
|
||||
Hyperf 的事件管理器預設由 [hyperf/event](https://github.com/hyperf/event) 實現,該元件亦可用於其它框架或應用,只需通過 Composer 將該元件引入即可。
|
||||
Hyperf 的事件管理器預設由 [hyperf/event](https://github.com/hyperf/event) 實現,該元件亦可用於其它框架或應用,只需透過 Composer 將該元件引入即可。
|
||||
|
||||
```bash
|
||||
composer require hyperf/event
|
||||
@ -17,11 +17,11 @@ composer require hyperf/event
|
||||
- `監聽器(Listener)` 是用於監聽 `事件(Event)` 的發生的監聽物件
|
||||
- `事件排程器(EventDispatcher)` 是用於觸發 `事件(Event)` 和管理 `監聽器(Listener)` 與 `事件(Event)` 之間的關係的管理者物件
|
||||
|
||||
用通俗易懂的例子來說明就是,假設我們存在一個 `UserService::register()` 方法用於註冊一個賬號,在賬號註冊成功後我們可以通過事件排程器觸發 `UserRegistered` 事件,由監聽器監聽該事件的發生,在觸發時進行某些操作,比如傳送使用者註冊成功簡訊,在業務發展的同時我們可能會希望在使用者註冊成功之後做更多的事情,比如傳送使用者註冊成功的郵件等待,此時我們就可以通過再增加一個監聽器監聽 `UserRegistered` 事件即可,無需在 `UserService::register()` 方法內部增加與之無關的程式碼。
|
||||
用通俗易懂的例子來說明就是,假設我們存在一個 `UserService::register()` 方法用於註冊一個賬號,在賬號註冊成功後我們可以透過事件排程器觸發 `UserRegistered` 事件,由監聽器監聽該事件的發生,在觸發時進行某些操作,比如傳送使用者註冊成功簡訊,在業務發展的同時我們可能會希望在使用者註冊成功之後做更多的事情,比如傳送使用者註冊成功的郵件等待,此時我們就可以透過再增加一個監聽器監聽 `UserRegistered` 事件即可,無需在 `UserService::register()` 方法內部增加與之無關的程式碼。
|
||||
|
||||
## 使用事件管理器
|
||||
|
||||
> 接下來我們會通過配置和註解兩種方式介紹監聽器,實際使用時,二者只需使用其一即可,如果既有註解又有配置,則會造成監聽器被多次觸發。
|
||||
> 接下來我們會透過配置和註解兩種方式介紹監聽器,實際使用時,二者只需使用其一即可,如果既有註解又有配置,則會造成監聽器被多次觸發。
|
||||
|
||||
### 定義一個事件
|
||||
|
||||
@ -77,7 +77,7 @@ class UserRegisteredListener implements ListenerInterface
|
||||
}
|
||||
```
|
||||
|
||||
#### 通過配置檔案註冊監聽器
|
||||
#### 透過配置檔案註冊監聽器
|
||||
|
||||
在定義完監聽器之後,我們需要讓其能被 `事件排程器(Dispatcher)` 發現,可以在 `config/autoload/listeners.php` 配置檔案 *(如不存在可自行建立)* 內新增該監聽器即可,監聽器的觸發順序根據該配置檔案的配置順序:
|
||||
|
||||
@ -88,9 +88,9 @@ return [
|
||||
];
|
||||
```
|
||||
|
||||
### 通過註解註冊監聽器
|
||||
### 透過註解註冊監聽器
|
||||
|
||||
Hyperf 還提供了一種更加簡便的監聽器註冊方式,就是通過 `@Listener` 註解註冊,只要將該註解定義在監聽器類上,且監聽器類處於 `Hyperf 註解掃描域` 內即可自動完成註冊,程式碼示例如下:
|
||||
Hyperf 還提供了一種更加簡便的監聽器註冊方式,就是透過 `@Listener` 註解註冊,只要將該註解定義在監聽器類上,且監聽器類處於 `Hyperf 註解掃描域` 內即可自動完成註冊,程式碼示例如下:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -123,13 +123,13 @@ class UserRegisteredListener implements ListenerInterface
|
||||
}
|
||||
```
|
||||
|
||||
在通過註解註冊監聽器時,我們可以通過設定 `priority` 屬性定義當前監聽器的順序,如 `@Listener(priority=1)` ,底層使用 `SplPriorityQueue` 結構儲存,`priority` 數字越大優先順序越高。
|
||||
在透過註解註冊監聽器時,我們可以透過設定 `priority` 屬性定義當前監聽器的順序,如 `@Listener(priority=1)` ,底層使用 `SplPriorityQueue` 結構儲存,`priority` 數字越大優先順序越高。
|
||||
|
||||
> 使用 `@Listener` 註解時需 `use Hyperf\Event\Annotation\Listener;` 名稱空間;
|
||||
|
||||
### 觸發事件
|
||||
|
||||
事件需要通過 `事件排程器(EventDispatcher)` 排程才能讓 `監聽器(Listener)` 監聽到,我們通過一段程式碼來演示如何觸發事件:
|
||||
事件需要透過 `事件排程器(EventDispatcher)` 排程才能讓 `監聽器(Listener)` 監聽到,我們透過一段程式碼來演示如何觸發事件:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -174,4 +174,4 @@ class UserService
|
||||
|
||||
### 最好只在 `Listener` 中注入 `ContainerInterface`。
|
||||
|
||||
最好只在 `Listener` 中注入 `ContainerInterface`,而其他的元件在 `process` 中通過 `container` 獲取。框架啟動開始時,會例項化 `EventDispatcherInterface`,這個時候還不是協程環境,如果 `Listener` 中注入了可能會觸發協程切換的類,就會導致框架啟動失敗。
|
||||
最好只在 `Listener` 中注入 `ContainerInterface`,而其他的元件在 `process` 中透過 `container` 獲取。框架啟動開始時,會例項化 `EventDispatcherInterface`,這個時候還不是協程環境,如果 `Listener` 中注入了可能會觸發協程切換的類,就會導致框架啟動失敗。
|
||||
|
@ -1,7 +1,7 @@
|
||||
# 異常處理器
|
||||
|
||||
在 `Hyperf` 裡,業務程式碼都執行在 `Worker 程序` 上,也就意味著一旦任意一個請求的業務存在沒有捕獲處理的異常的話,都會導致對應的 `Worker 程序` 被中斷退出,這對服務而言也是不能接受的,捕獲異常並輸出合理的報錯內容給客戶端也是更加友好的。
|
||||
我們可以通過對各個 `server` 定義不同的 `異常處理器(ExceptionHandler)`,一旦業務流程存在沒有捕獲的異常,都會被傳遞到已註冊的 `異常處理器(ExceptionHandler)` 去處理。
|
||||
我們可以透過對各個 `server` 定義不同的 `異常處理器(ExceptionHandler)`,一旦業務流程存在沒有捕獲的異常,都會被傳遞到已註冊的 `異常處理器(ExceptionHandler)` 去處理。
|
||||
|
||||
## 自定義一個異常處理
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# 檔案系統
|
||||
|
||||
檔案系統元件集成了 PHP 生態中大名鼎鼎的 `League\Flysystem` (這也是 Laravel 等諸多知名框架的底層庫)。通過合理抽象,程式不必感知儲存引擎究竟是本地硬碟還是雲伺服器,實現解耦。本元件對常用的雲端儲存服務提供了協程化支援。
|
||||
檔案系統元件集成了 PHP 生態中大名鼎鼎的 `League\Flysystem` (這也是 Laravel 等諸多知名框架的底層庫)。透過合理抽象,程式不必感知儲存引擎究竟是本地硬碟還是雲伺服器,實現解耦。本元件對常用的雲端儲存服務提供了協程化支援。
|
||||
|
||||
## 安裝
|
||||
|
||||
@ -106,7 +106,7 @@ php bin/hyperf.php vendor:publish hyperf/filesystem
|
||||
|
||||
## 使用
|
||||
|
||||
通過 DI 注入 `League\Flysystem\Filesystem` 即可使用。
|
||||
透過 DI 注入 `League\Flysystem\Filesystem` 即可使用。
|
||||
|
||||
API 如下:
|
||||
|
||||
@ -192,7 +192,7 @@ class IndexController
|
||||
|
||||
### 配置靜態資源
|
||||
|
||||
如果您希望通過 http 訪問上傳到本地的檔案,請在 `config/autoload/server.php` 配置中增加以下配置。
|
||||
如果您希望透過 http 訪問上傳到本地的檔案,請在 `config/autoload/server.php` 配置中增加以下配置。
|
||||
|
||||
```
|
||||
return [
|
||||
@ -210,7 +210,7 @@ return [
|
||||
|
||||
1. S3 儲存請確認安裝 `hyperf/guzzle` 元件以提供協程化支援。阿里雲、七牛雲、騰訊云云儲存請[開啟 Curl Hook](/zh-tw/coroutine?id=swoole-runtime-hook-level)來使用協程。因 Curl Hook 的引數支援性問題,請使用 Swoole 4.4.13 以上版本。
|
||||
2. minIO, ceph radosgw 等私有物件儲存方案均支援 S3 協議,可以使用 S3 介面卡。
|
||||
3. 使用 Local 驅動時,根目錄是配置好的地址,而不是作業系統的根目錄。例如,Local 驅動 `root` 設定為 `/var/www`, 則本地磁碟上的 `/var/www/public/file.txt` 通過 flysystem API 訪問時應使用 `/public/file.txt` 或 `public/file.txt` 。
|
||||
3. 使用 Local 驅動時,根目錄是配置好的地址,而不是作業系統的根目錄。例如,Local 驅動 `root` 設定為 `/var/www`, 則本地磁碟上的 `/var/www/public/file.txt` 透過 flysystem API 訪問時應使用 `/public/file.txt` 或 `public/file.txt` 。
|
||||
4. 以阿里雲 OSS 為例,1 核 1 程序讀操作效能對比:
|
||||
|
||||
```bash
|
||||
|
@ -1,6 +1,6 @@
|
||||
# Guzzle HTTP 客戶端
|
||||
|
||||
[hyperf/guzzle](https://github.com/hyperf/guzzle) 元件基於 Guzzle 進行協程處理,通過 Swoole HTTP 客戶端作為協程驅動替換到 Guzzle 內,以達到 HTTP 客戶端的協程化。
|
||||
[hyperf/guzzle](https://github.com/hyperf/guzzle) 元件基於 Guzzle 進行協程處理,透過 Swoole HTTP 客戶端作為協程驅動替換到 Guzzle 內,以達到 HTTP 客戶端的協程化。
|
||||
|
||||
## 安裝
|
||||
|
||||
@ -139,7 +139,7 @@ $client = make(Client::class, [
|
||||
|
||||
## 使用 `ClassMap` 替換 `GuzzleHttp\Client`
|
||||
|
||||
如果第三方元件並沒有提供可以替換 `Handler` 的介面,我們也可以通過 `ClassMap` 功能,直接替換 `Client` 來達到將客戶端協程化的目的。
|
||||
如果第三方元件並沒有提供可以替換 `Handler` 的介面,我們也可以透過 `ClassMap` 功能,直接替換 `Client` 來達到將客戶端協程化的目的。
|
||||
|
||||
> 當然,也可以使用 SWOOLE_HOOK 達到相同的目的。
|
||||
|
||||
|
@ -14,9 +14,9 @@ composer require hyperf/jet
|
||||
|
||||
## 註冊協議
|
||||
|
||||
> 註冊協議不是必須的一個步驟,但您可以通過 ProtocolManager 管理所有的協議。
|
||||
> 註冊協議不是必須的一個步驟,但您可以透過 ProtocolManager 管理所有的協議。
|
||||
|
||||
您可以通過 `Hyperf\Jet\ProtocolManager` 類來註冊管理任意的協議,每個協議會包含 Transporter, Packer, DataFormatter and PathGenerator 幾個基本的元件,您可以註冊一個 JSONRPC 協議,如下:
|
||||
您可以透過 `Hyperf\Jet\ProtocolManager` 類來註冊管理任意的協議,每個協議會包含 Transporter, Packer, DataFormatter and PathGenerator 幾個基本的元件,您可以註冊一個 JSONRPC 協議,如下:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -37,9 +37,9 @@ ProtocolManager::register($protocol = 'jsonrpc', [
|
||||
|
||||
## 註冊服務
|
||||
|
||||
> 註冊服務不是必須的一個步驟,但您可以通過 ServiceManager 管理所有的服務。
|
||||
> 註冊服務不是必須的一個步驟,但您可以透過 ServiceManager 管理所有的服務。
|
||||
|
||||
在您往 `Hyperf\Jet\ProtocolManager` 註冊了一個協議之後,您可以通過 `Hyperf\Jet\ServiceManager` 將協議繫結到任意的服務上,如下:
|
||||
在您往 `Hyperf\Jet\ProtocolManager` 註冊了一個協議之後,您可以透過 `Hyperf\Jet\ServiceManager` 將協議繫結到任意的服務上,如下:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -55,9 +55,9 @@ ServiceManager::register($service = 'CalculatorService', $protocol = 'jsonrpc',
|
||||
|
||||
## 呼叫 RPC 方法
|
||||
|
||||
### 通過 ClientFactory 呼叫
|
||||
### 透過 ClientFactory 呼叫
|
||||
|
||||
在您註冊完協議與服務之後,您可以通過 `Hyperf/Jet/ClientFactory` 來獲得您的服務的客戶端,如下所示:
|
||||
在您註冊完協議與服務之後,您可以透過 `Hyperf/Jet/ClientFactory` 來獲得您的服務的客戶端,如下所示:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -67,7 +67,7 @@ $clientFactory = new ClientFactory();
|
||||
$client = $clientFactory->create($service = 'CalculatorService', $protocol = 'jsonrpc');
|
||||
```
|
||||
|
||||
當您擁有 client 物件後,您可以通過該物件呼叫任意的遠端方法,如下:
|
||||
當您擁有 client 物件後,您可以透過該物件呼叫任意的遠端方法,如下:
|
||||
|
||||
```php
|
||||
// 呼叫遠端方法 `add` 並帶上引數 `1` 和 `2`
|
||||
@ -77,7 +77,7 @@ $result = $client->add(1, 2);
|
||||
|
||||
當您呼叫一個不存在的遠端方法時,客戶端會丟擲一個 `Hyperf\Jet\Exception\ServerException` 異常。
|
||||
|
||||
### 通過自定義客戶端呼叫
|
||||
### 透過自定義客戶端呼叫
|
||||
|
||||
您可以建立一個 `Hyperf\Jet\AbstractClient` 的子類作為自定義的客戶端類,來完成遠端方法的呼叫,比如,您希望定義一個 `CalculatorService` 服務的 `jsonrpc` 協議的客戶端類,您可以先定義一個 `CalculatorService` 類,如下所示:
|
||||
|
||||
@ -105,16 +105,16 @@ class CalculatorService extends AbstractClient
|
||||
?DataFormatterInterface $dataFormatter = null,
|
||||
?PathGeneratorInterface $pathGenerator = null
|
||||
) {
|
||||
// 這裡指定 transporter,您仍然可以通過 ProtocolManager 來獲得 transporter 或從建構函式傳遞
|
||||
// 這裡指定 transporter,您仍然可以透過 ProtocolManager 來獲得 transporter 或從建構函式傳遞
|
||||
$transporter = new StreamSocketTransporter('127.0.0.1', 9503);
|
||||
// 這裡指定 packer,您仍然可以通過 ProtocolManager 來獲得 packer 或從建構函式傳遞
|
||||
// 這裡指定 packer,您仍然可以透過 ProtocolManager 來獲得 packer 或從建構函式傳遞
|
||||
$packer = new JsonEofPacker();
|
||||
parent::__construct($service, $transporter, $packer, $dataFormatter, $pathGenerator);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
現在,您可以通過該類來直接呼叫遠端方法了,如下所示:
|
||||
現在,您可以透過該類來直接呼叫遠端方法了,如下所示:
|
||||
|
||||
```php
|
||||
// 呼叫遠端方法 `add` 並帶上引數 `1` 和 `2`
|
||||
|
@ -24,12 +24,12 @@ composer require hyperf/rpc-client
|
||||
|
||||
## 使用
|
||||
|
||||
服務有兩種角色,一種是 `服務提供者(ServiceProvider)`,即為其它服務提供服務的服務,另一種是 `服務消費者(ServiceConsumer)`,即依賴其它服務的服務,一個服務既可能是 `服務提供者(ServiceProvider)`,同時又是 `服務消費者(ServiceConsumer)`。而兩者直接可以通過 `服務契約` 來定義和約束介面的呼叫,在 Hyperf 裡,可直接理解為就是一個 `介面類(Interface)`,通常來說這個介面類會同時出現在提供者和消費者下。
|
||||
服務有兩種角色,一種是 `服務提供者(ServiceProvider)`,即為其它服務提供服務的服務,另一種是 `服務消費者(ServiceConsumer)`,即依賴其它服務的服務,一個服務既可能是 `服務提供者(ServiceProvider)`,同時又是 `服務消費者(ServiceConsumer)`。而兩者直接可以透過 `服務契約` 來定義和約束介面的呼叫,在 Hyperf 裡,可直接理解為就是一個 `介面類(Interface)`,通常來說這個介面類會同時出現在提供者和消費者下。
|
||||
|
||||
### 定義服務提供者
|
||||
|
||||
目前僅支援通過註解的形式來定義 `服務提供者(ServiceProvider)`,後續迭代會增加配置的形式。
|
||||
我們可以直接通過 `@RpcService` 註解對一個類進行定義即可釋出這個服務了:
|
||||
目前僅支援透過註解的形式來定義 `服務提供者(ServiceProvider)`,後續迭代會增加配置的形式。
|
||||
我們可以直接透過 `@RpcService` 註解對一個類進行定義即可釋出這個服務了:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -39,7 +39,7 @@ namespace App\JsonRpc;
|
||||
use Hyperf\RpcServer\Annotation\RpcService;
|
||||
|
||||
/**
|
||||
* 注意,如希望通過服務中心來管理服務,需在註解內增加 publishTo 屬性
|
||||
* 注意,如希望透過服務中心來管理服務,需在註解內增加 publishTo 屬性
|
||||
*/
|
||||
#[RpcService(name: "CalculatorService", protocol: "jsonrpc-http", server: "jsonrpc-http")]
|
||||
class CalculatorService implements CalculatorServiceInterface
|
||||
@ -155,8 +155,8 @@ return [
|
||||
### 釋出到服務中心
|
||||
|
||||
目前僅支援釋出服務到 `consul`、`nacos`,後續會增加其它服務中心。
|
||||
釋出服務到 `consul` 在 Hyperf 也是非常容易的一件事情,通過 `composer require hyperf/service-governance-consul` 引用元件(如果已安裝則可忽略該步驟),然後再在 `config/autoload/services.php` 配置檔案內配置 `drivers.consul` 配置即可。
|
||||
釋出服務到 `nacos` 在也是類似,通過 `composer require hyperf/service-governance-nacos` 引用元件(如果已安裝則可忽略該步驟),然後再在 `config/autoload/services.php` 配置檔案內配置 `drivers.nacos` 配置即可,示例如下:
|
||||
釋出服務到 `consul` 在 Hyperf 也是非常容易的一件事情,透過 `composer require hyperf/service-governance-consul` 引用元件(如果已安裝則可忽略該步驟),然後再在 `config/autoload/services.php` 配置檔案內配置 `drivers.consul` 配置即可。
|
||||
釋出服務到 `nacos` 在也是類似,透過 `composer require hyperf/service-governance-nacos` 引用元件(如果已安裝則可忽略該步驟),然後再在 `config/autoload/services.php` 配置檔案內配置 `drivers.nacos` 配置即可,示例如下:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -202,7 +202,7 @@ return [
|
||||
|
||||
#### 自動建立代理消費者類
|
||||
|
||||
您可通過在 `config/autoload/services.php` 配置檔案內進行一些簡單的配置,即可通過動態代理自動建立消費者類。
|
||||
您可透過在 `config/autoload/services.php` 配置檔案內進行一些簡單的配置,即可透過動態代理自動建立消費者類。
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -226,7 +226,7 @@ return [
|
||||
'protocol' => 'consul',
|
||||
'address' => 'http://127.0.0.1:8500',
|
||||
],
|
||||
// 如果沒有指定上面的 registry 配置,即為直接對指定的節點進行消費,通過下面的 nodes 引數來配置服務提供者的節點資訊
|
||||
// 如果沒有指定上面的 registry 配置,即為直接對指定的節點進行消費,透過下面的 nodes 引數來配置服務提供者的節點資訊
|
||||
'nodes' => [
|
||||
['host' => '127.0.0.1', 'port' => 9504],
|
||||
],
|
||||
@ -264,13 +264,13 @@ return [
|
||||
];
|
||||
```
|
||||
|
||||
在應用啟動時會自動建立客戶端類的代理物件,並在容器中使用配置項 `id` 的值(如果未設定,會使用配置項 `service` 值代替)來新增繫結關係,這樣就和手工編寫的客戶端類一樣,通過注入 `CalculatorServiceInterface` 介面來直接使用客戶端。
|
||||
在應用啟動時會自動建立客戶端類的代理物件,並在容器中使用配置項 `id` 的值(如果未設定,會使用配置項 `service` 值代替)來新增繫結關係,這樣就和手工編寫的客戶端類一樣,透過注入 `CalculatorServiceInterface` 介面來直接使用客戶端。
|
||||
|
||||
> 當服務提供者使用介面類名釋出服務名,在服務消費端只需要設定配置項 `name` 值為介面類名,不需要重複設定配置項 `id` 和 `service`。
|
||||
|
||||
#### 手動建立消費者類
|
||||
|
||||
如您對消費者類有更多的需求,您可通過手動建立一個消費者類來實現,只需要定義一個類及相關屬性即可。
|
||||
如您對消費者類有更多的需求,您可透過手動建立一個消費者類來實現,只需要定義一個類及相關屬性即可。
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -313,7 +313,7 @@ return [
|
||||
'protocol' => 'consul',
|
||||
'address' => 'http://127.0.0.1:8500',
|
||||
],
|
||||
// 如果沒有指定上面的 registry 配置,即為直接對指定的節點進行消費,通過下面的 nodes 引數來配置服務提供者的節點資訊
|
||||
// 如果沒有指定上面的 registry 配置,即為直接對指定的節點進行消費,透過下面的 nodes 引數來配置服務提供者的節點資訊
|
||||
'nodes' => [
|
||||
['host' => '127.0.0.1', 'port' => 9504],
|
||||
],
|
||||
@ -323,7 +323,7 @@ return [
|
||||
```
|
||||
|
||||
|
||||
這樣我們便可以通過 `CalculatorService` 類來實現對服務的消費了,為了讓這裡的關係邏輯更加的合理,還應該在 `config/autoload/dependencies.php` 內定義 `CalculatorServiceInterface` 和 `CalculatorServiceConsumer` 的關係,示例如下:
|
||||
這樣我們便可以透過 `CalculatorService` 類來實現對服務的消費了,為了讓這裡的關係邏輯更加的合理,還應該在 `config/autoload/dependencies.php` 內定義 `CalculatorServiceInterface` 和 `CalculatorServiceConsumer` 的關係,示例如下:
|
||||
|
||||
```php
|
||||
return [
|
||||
@ -331,13 +331,13 @@ return [
|
||||
];
|
||||
```
|
||||
|
||||
這樣便可以通過注入 `CalculatorServiceInterface` 介面來使用客戶端了。
|
||||
這樣便可以透過注入 `CalculatorServiceInterface` 介面來使用客戶端了。
|
||||
|
||||
#### 配置複用
|
||||
|
||||
通常來說,一個服務消費者會同時消費多個服務提供者,當我們通過服務中心來發現服務提供者時, `config/autoload/services.php` 配置檔案內就可能會重複配置很多次 `registry` 配置,但通常來說,我們的服務中心可能是統一的,也就意味著多個服務消費者配置都是從同樣的服務中心去拉取節點資訊,此時我們可以通過 `PHP 變數` 或 `迴圈` 等 PHP 程式碼來實現配置檔案的生成。
|
||||
通常來說,一個服務消費者會同時消費多個服務提供者,當我們透過服務中心來發現服務提供者時, `config/autoload/services.php` 配置檔案內就可能會重複配置很多次 `registry` 配置,但通常來說,我們的服務中心可能是統一的,也就意味著多個服務消費者配置都是從同樣的服務中心去拉取節點資訊,此時我們可以透過 `PHP 變數` 或 `迴圈` 等 PHP 程式碼來實現配置檔案的生成。
|
||||
|
||||
##### 通過 PHP 變數生成配置
|
||||
##### 透過 PHP 變數生成配置
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -360,7 +360,7 @@ return [
|
||||
];
|
||||
```
|
||||
|
||||
##### 通過迴圈生成配置
|
||||
##### 透過迴圈生成配置
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -368,7 +368,7 @@ return [
|
||||
// 此處省略了其它同層級的配置
|
||||
'consumers' => value(function () {
|
||||
$consumers = [];
|
||||
// 這裡示例自動建立代理消費者類的配置形式,顧存在 name 和 service 兩個配置項,這裡的做法不是唯一的,僅說明可以通過 PHP 程式碼來生成配置
|
||||
// 這裡示例自動建立代理消費者類的配置形式,顧存在 name 和 service 兩個配置項,這裡的做法不是唯一的,僅說明可以透過 PHP 程式碼來生成配置
|
||||
// 下面的 FooServiceInterface 和 BarServiceInterface 僅示例多服務,並不是在文件示例中真實存在的
|
||||
$services = [
|
||||
'FooService' => App\JsonRpc\FooServiceInterface::class,
|
||||
@ -458,7 +458,7 @@ var_dump($result->value);
|
||||
|
||||
### 使用 JsonRpcPoolTransporter
|
||||
|
||||
框架提供了基於連線池的 `Transporter`,可以有效避免高併發時,建立過多連線的問題。這裡可以通過替換 `JsonRpcTransporter` 的方式,使用 `JsonRpcPoolTransporter`。
|
||||
框架提供了基於連線池的 `Transporter`,可以有效避免高併發時,建立過多連線的問題。這裡可以透過替換 `JsonRpcTransporter` 的方式,使用 `JsonRpcPoolTransporter`。
|
||||
|
||||
修改 `dependencies.php` 檔案
|
||||
|
||||
|
@ -20,7 +20,7 @@ composer require hyperf/kafka
|
||||
|
||||
### 配置
|
||||
|
||||
`kafka` 元件的配置檔案預設位於 `config/autoload/kafka.php` 內,如該檔案不存在,可通過 `php bin/hyperf.php vendor:publish hyperf/kafka` 命令來將釋出對應的配置檔案。
|
||||
`kafka` 元件的配置檔案預設位於 `config/autoload/kafka.php` 內,如該檔案不存在,可透過 `php bin/hyperf.php vendor:publish hyperf/kafka` 命令來將釋出對應的配置檔案。
|
||||
|
||||
預設配置檔案如下:
|
||||
|
||||
@ -108,13 +108,13 @@ return [
|
||||
|
||||
### 建立消費者
|
||||
|
||||
通過 gen:kafka-consumer 命令可以快速的生成一個 消費者(Consumer) 對訊息進行消費。
|
||||
透過 gen:kafka-consumer 命令可以快速的生成一個 消費者(Consumer) 對訊息進行消費。
|
||||
|
||||
```bash
|
||||
php bin/hyperf.php gen:kafka-consumer KafkaConsumer
|
||||
```
|
||||
|
||||
您也可以通過使用 `Hyperf\Kafka\Annotation\Consumer` 註解來對一個 `Hyperf/Kafka/AbstractConsumer` 抽象類的子類進行宣告,來完成一個 `消費者(Consumer)` 的定義,其中 `Hyperf\Kafka\Annotation\Consumer` 註解和抽象類均包含以下屬性:
|
||||
您也可以透過使用 `Hyperf\Kafka\Annotation\Consumer` 註解來對一個 `Hyperf/Kafka/AbstractConsumer` 抽象類的子類進行宣告,來完成一個 `消費者(Consumer)` 的定義,其中 `Hyperf\Kafka\Annotation\Consumer` 註解和抽象類均包含以下屬性:
|
||||
|
||||
| 配置 | 型別 | 註解或抽象類預設值 | 備註 |
|
||||
| :--------: | :----------------: | :----------------: | :----------------------------------: |
|
||||
@ -151,7 +151,7 @@ class KafkaConsumer extends AbstractConsumer
|
||||
|
||||
### 投遞訊息
|
||||
|
||||
您可以通過呼叫 `Hyperf\Kafka\Producer::send(string $topic, ?string $value, ?string $key = null, array $headers = [], ?int $partitionIndex = null)` 方法來向 `kafka` 投遞訊息, 下面是在 `Controller` 進行訊息投遞的一個示例:
|
||||
您可以透過呼叫 `Hyperf\Kafka\Producer::send(string $topic, ?string $value, ?string $key = null, array $headers = [], ?int $partitionIndex = null)` 方法來向 `kafka` 投遞訊息, 下面是在 `Controller` 進行訊息投遞的一個示例:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -176,7 +176,7 @@ class IndexController extends AbstractController
|
||||
|
||||
### 一次性投遞多條訊息
|
||||
|
||||
`Hyperf\Kafka\Producer::sendBatch(array $messages)` 方法來向 `kafka` 批量的投遞訊息, 下面是在 `Controller` 進行訊息投遞的一個示例:
|
||||
`Hyperf\Kafka\Producer::sendBatch(array $messages)` 方法來向 `kafka` 批次的投遞訊息, 下面是在 `Controller` 進行訊息投遞的一個示例:
|
||||
|
||||
|
||||
```php
|
||||
|
@ -3,10 +3,10 @@
|
||||
## 框架生命週期
|
||||
|
||||
Hyperf 是運行於 [Swoole](http://github.com/swoole/swoole-src) 之上的,想要理解透徹 Hyperf 的生命週期,那麼理解 [Swoole](http://github.com/swoole/swoole-src) 的生命週期也至關重要。
|
||||
Hyperf 的命令管理預設由 [symfony/console](https://github.com/symfony/console) 提供支援*(如果您希望更換該元件您也可以通過改變 skeleton 的入口檔案更換成您希望使用的元件)*,在執行 `php bin/hyperf.php start` 後,將由 `Hyperf\Server\Command\StartServer` 命令類接管,並根據配置檔案 `config/autoload/server.php` 內定義的 `Server` 逐個啟動。
|
||||
Hyperf 的命令管理預設由 [symfony/console](https://github.com/symfony/console) 提供支援*(如果您希望更換該元件您也可以透過改變 skeleton 的入口檔案更換成您希望使用的元件)*,在執行 `php bin/hyperf.php start` 後,將由 `Hyperf\Server\Command\StartServer` 命令類接管,並根據配置檔案 `config/autoload/server.php` 內定義的 `Server` 逐個啟動。
|
||||
關於依賴注入容器的初始化工作,我們並沒有由元件來實現,因為一旦交由元件來實現,這個耦合就會非常的明顯,所以在預設的情況下,是由入口檔案來載入 `config/container.php` 來實現的。
|
||||
|
||||
## 請求與協程生命週期
|
||||
|
||||
Swoole 在處理每個連線時,會預設建立一個協程去處理,主要體現在 `onRequest`、`onReceive`、`onConnect` 事件,所以可以理解為每個請求都是一個協程,由於建立協程也是個常規操作,所以一個請求協程裡面可能會包含很多個協程,同一個程序內協程之間是記憶體共享的,但排程順序是非順序的,且協程間本質上是相互獨立的沒有父子關係,所以對每個協程的狀態處理都需要通過 [協程上下文](zh-tw/coroutine.md#協程上下文) 來管理。
|
||||
Swoole 在處理每個連線時,會預設建立一個協程去處理,主要體現在 `onRequest`、`onReceive`、`onConnect` 事件,所以可以理解為每個請求都是一個協程,由於建立協程也是個常規操作,所以一個請求協程裡面可能會包含很多個協程,同一個程序內協程之間是記憶體共享的,但排程順序是非順序的,且協程間本質上是相互獨立的沒有父子關係,所以對每個協程的狀態處理都需要透過 [協程上下文](zh-tw/coroutine.md#協程上下文) 來管理。
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user