Hyperf 3.0 釋出,PHP 新時代

huangzhhui發表於2023-01-03

回顧

在過去的一年半時間裡,Hyperf 2.2 共釋出了 35 個小版本,使 Hyperf 達到了一個前所未有的高度,這裡也獲得了一些不錯的資料反饋。

Hyperf 在 GitHubGitee 上的關注度也得到了顯著提升,分別獲得了 4.9k791star,整體關注度增長也很穩定。

4.9k star

Hyperf 框架的安裝量也達到了 90萬次,每天都有約 1300次的安裝,這也表明了 Hyperf 已經廣泛應用於相關行業中並支撐了大量的系統執行。

超過 90萬次 安裝

Hyperf 組織下的有效 repo 更是達到了約 140個(去除掉 Archive 專案後),維護工作量空前巨大,但迭代仍然高頻。

超過 140 個 repos

感謝 Hyperf 團隊全體成員的辛勤以及貢獻,同時也感謝所有的 PR 貢獻者,沒有你們的參與也就沒有今天的 Hyperf。

Thanks ALL Contributors

Love and Peace

Hyperf 3.0 新時代

Hyperf 3.0 帶來了很多非常有意思的新能力,其中一些新能力不乏是 PHP 領域裡面前所未有的,當然這些新能力也脫離不了其他開源社群的積極發展,包括但不限於 PHPSwooleSwowPHPMicroDTMSeata 等開源社群,也衷心希望大家在閒暇時間可以為這些開源社群也貢獻出自己的一份力,搭上一磚一瓦,共建更加美好的未來。

原生註解(Attribute)

隨著 PHP 8.1、8.2 的釋出,給 PHP 帶來了很多新的特性,其中與 Hyperf 最為相關的就是 PHP 的原生註解(Attribute)了,Hyperf 3.0 也放棄了過往採用的基於註釋解析的註解功能實現,轉而採用 PHP 的原生註解,當然對應依賴的 PHP 版本,也將調整為最低要求 PHP 8.0。

我們以一個最簡單的 Controller 案例來呈現新的原生註解的使用:

<?php
declare(strict_types=1);

namespace App\Controller;

use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\RequestMapping;

#[Controller]
class IndexController
{
    // Hyperf 會自動為此方法生成一個 /index/index 的路由,允許透過 GET 或 POST 方式請求
    #[RequestMapping(path: "index", methods: "get,post")]
    public function index(RequestInterface $request)
    {
        // 從請求中獲得 id 引數
        $id = $request->input('id', 1);
        return (string)$id;
    }
}

同時隨著原生註解的應用,在 3.0 中也能夠支援在同一個位置重複應用同一個註解了,比如過往在一個 Controller Action 想要應用多個 Middleware 時,需要透過 @Middlewares 註解包含多個 @Middleware 註解實現應用,而在 3.0 則可直接書寫多個 @Middleware 註解實現該應用。同時在 3.0 中,註解也可以應用在方法的引數上,以實現一些針對方法引數定義、引數解析等功能。

從 註釋註解 調整為 原生註解,也無需擔憂過往專案的遷移改造工作量,Hyperf 也提供了對應的工具一鍵自動轉換,只需要在 2.2 時引入 hyperf/code-generator 元件,並執行 php bin/hyperf.php code:generate -D app 命令,即可將 app 資料夾內的註釋註解自動轉為原生註解,輕鬆省力~

分散式事務

在過去的一年裡,Hyperf 團隊也為 PHP 領域孵化了兩個前所未有的分散式事務元件並貢獻到對應的開源社群,對應 DTM (首個基於 Go 語言實現的流行分散式事務管理器) 與 Seata (由阿里巴巴開源的流行分散式事務管理器) 兩款主流的開源分散式事務管理器,分別是 dtm-php/dtm-clientseata/seata-php ,其中 dtm-php 是實現了 dtm 完整功能的分散式事務客戶端,已支援 TCC模式SagaXA二階段訊息模式的分散式事務模式,並分別實現了與 DTM Server 以 HTTP 協議gRPC 協議 通訊,該客戶端可安全執行於 PHP-FPM 和 Swoole 協程環境中,更是對 Hyperf 框架做了更加易用的功能支援,可應用於生產環境中,而 seata-php 仍在開發迭代中,尚未能用於生產環境,也希望能有更多人參與進來共同迭代。

我們也以一個簡單的例子來說明如何在 Hyperf 中實現一個 TCC 分散式事務的呼叫,其它分散式事務模式可查閱 dtm-php repo 的 README 檔案,或 Hyperf 3.0 文件關於分散式事務一章。

<?php
namespace App\Controller;

use DtmClient\TCC;
use DtmClient\TransContext;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\GetMapping;
use Throwable;

#[Controller(prefix: '/tcc')]
class TccController
{

    protected string $serviceUri = 'http://127.0.0.1:9501';

    #[Inject]
    protected TCC $tcc;

    #[GetMapping(path: 'successCase')]
    public function successCase()
    {
        try {
            $this->tcc->globalTransaction(function (TCC $tcc) {
                // 建立子事務 A 的呼叫資料
                $tcc->callBranch(
                    // 呼叫 Try 方法的引數
                    ['amount' => 30],
                    // Try 方法的 URL
                    $this->serviceUri . '/tcc/transA/try',
                    // Confirm 方法的 URL
                    $this->serviceUri . '/tcc/transA/confirm',
                    // Cancel 方法的 URL
                    $this->serviceUri . '/tcc/transA/cancel'
                );
                // 建立子事務 B 的呼叫資料,以此類推
                $tcc->callBranch(
                    ['amount' => 30],
                    $this->serviceUri . '/tcc/transB/try',
                    $this->serviceUri . '/tcc/transB/confirm',
                    $this->serviceUri . '/tcc/transB/cancel'
                );
            });
        } catch (Throwable $e) {
            var_dump($e->getMessage(), $e->getTraceAsString());
        }
        // 透過 TransContext::getGid() 獲得 全域性事務ID 並返回
        return TransContext::getGid();
    }

}

至於其它事務模式,如 SagaXA二階段訊息模式等,可以具體查閱 dtm-php/dtm-client 倉庫的 Readme 檔案或 Hyperf 3.0 的相關文件。

Swow 網路引擎

實際上在 Hyperf 2.2 中,就已經支援了 Swow 網路引擎的執行,隨著 Swow 1.0 正式版的釋出,在 Hyperf 3.0 中,我們也把 Swow 的應用提高到了一個更高的高度,Swow 實現了一套有史以來最完整的 PHP 協程模型,它全面釋放了 PHP 的真正實力,使得開發者可以做到以往難以想象的事情,對比 Swoole 它具備更好的相容性可除錯性可程式設計性,它甚至能使 Hyperf 執行於原生 Windows 環境下而無需藉助 WSL 或 Docker,同時也提供了 SDBWatchdog 工具對協程執行進行除錯和監控,極大的提升了 Hyperf 的可除錯性。

我們提供了一個全新的 Skeleton 骨架專案用於快速建立一個基於 Swow 網路引擎的 Hyperf 應用,以下是一個簡單的透過 Composer 建立應用的流程:

composer create-project hyperf/swow-skeleton:dev-master 

建立後,確保您的 PHP 環境已經安裝好了 Swow 擴充套件,便可直接透過 php bin/hyperf.php start 命令啟動服務,整體使用與原來無異,Hyperf 底層已做好了適配。在 Windows 環境中也只需在 CMD 或者 Poweshell 中執行即可哦~

SDB 協程偵錯程式

SDB 是一款使用 PHP 語言編寫的協程偵錯程式工具,使用上類似於 GDB,它具有以下的幾個優點:

  1. 使用簡單,只需要一行程式碼即可開啟;
  2. 無需埠,可直接執行在 TTY 上;
  3. 零成本,可在生產環境使用,不影響效能;
  4. 功能強大,深度定製,量身打造類微型作業系統;

透過 SDB,您可以對執行中的 Hyperf 應用進行互動,以實現檢視當前所有協程狀態窺視協程進入指定協程檢視呼叫棧打斷點單步除錯檢視及修改變數除錯掃描殭屍協程Kill 協程等操作,真正意義上的將 PHP 協程帶到了工程化的實用階段

Watchdog

Watchdog 為 PHP 提供了 CPU 排程能力,其核心原理是 Watchdog 執行緒會定期檢查其它執行緒中協程的活躍度情況,若發現工作執行緒中的協程不再活躍,則透過 ZendVM 的中斷機制對其進行狀態確認,若 VM 中斷失敗,則表明工作執行緒陷入了系統呼叫阻塞,觸發告警;若 VM 中斷成功,則表明工作執行緒陷入了 CPU 密集運算或死迴圈,則立即觸發使用者設定的排程規則進行排程。

透過 Watchdog 可以實現 可程式設計的協程排程機制,可以非常方便的解決過往頭疼的 CPU 飢餓 問題,以下是一些用法的演示:

// 執行超過 1ms 就讓出控制權
\Swow\WatchDog::run(1 * 1000 * 1000);

// 執行超過 1ms 就讓出 10ms,排程失敗並超過 5ms 時視為系統呼叫阻塞
\Swow\WatchDog::run(1 * 1000 * 1000, 5 * 1000 * 1000, 10);

// 可程式設計方式,函式會在程式阻塞 100ms 後觸發
$alertCountMap = new WeakMap();
\Swow\WatchDog::run(quantum: 100 * 1000 * 1000, alerter: static function () use ($alertCountMap): void {
    $coroutine = Coroutine::getCurrent();
    $alertCount = ($alertCountMap[$coroutine] ??= 0) + 1;
    $alertCountMap[$coroutine] = $alertCount;
    echo 'CPU starvation occurred, suspend this coroutine...' . PHP_EOL;
    sleep(0);
    if ($alertCount > 5) {
        echo 'Kill the bad guy' . PHP_EOL;
        $coroutine->kill();
    }
});

更多用法

關於 SDBWatchDog 以及更多用法目前文件可能尚未完善,我們接下來也會編寫多篇文章來闡述用法,也會盡快完善相關文件~

Box

Box 是一個致力於幫助提升 PHP 應用程式的程式設計體驗的工具,尤其有助於 Hyperf 應用,可以用於管理 PHP 環境和相關依賴,同時提供將 PHP 應用程式打包為二進位制程式的能力,還提供反向代理服務來管理和部署 Swoole/Swow 服務。這些能力也是前所未有的,特別是將 Hyperf 或 PHP 應用打包為二進位制程式的能力,打包好的程式,可以不依賴系統的 PHP 環境單獨執行,以達到類似於 Go 語言的打包能力,這些能力也得益於 phpmicro 的發展,而 Box 則是站在巨人的肩膀上,將這些能力以更加簡單易用的方式提供給大家使用~

以下是一個透過下載 Box 到建立一個 Hyperf 應用,並執行的簡單案例:

安裝 Box

// Mac
wget https://github.com/hyperf/box/releases/download/v0.5.5/box_x86_64_macos -O box
sudo mv ./box /usr/local/bin/box
sudo chmod 755 /usr/local/bin/box
// 確保 /usr/local/bin/box 在你的 $PATH 環境中,或者將 `box` 放到你想要的任意 $PATH 路徑中


// Linux x86_64
wget https://github.com/hyperf/box/releases/download/v0.5.5/box_x86_64_linux -O box
sudo mv ./box /usr/local/bin/box
sudo chmod 755 /usr/local/bin/box
// 確保 /usr/local/bin/box 在你的 $PATH 環境中,或者將 `box` 放到你想要的任意 $PATH 路徑中


// Windows
curl -o box.exe https://github.com/hyperf/box/releases/download/v0.5.5/box_x64_windows.exe
// 將 `box.exe` 放到你想要的任意 Path 環境變數路徑中,同時 Windows 版本在執行時需要在命令列中使用 `box.exe` 而不是 `box`

初始化 Github Access Token

Box 需要一個 Github 訪問令牌來請求 Github API,以便於從 GitHub Actions 的 Artifacts 中檢索包的版本。

  1. 建立 Github Access Tokenworkflow 範圍需要勾選;
  2. 執行 box config set github.access-token <Your Token> 命令來設定您的 token

我們將在 v0.6 版本讓使用 Box 前無需設定 Github Access Token,以提供更加簡便的使用體驗,請期待~

透過 Box 初始化 PHP 環境並啟動 Hyperf

// 透過 box 安裝 PHP 8.1,此安裝不會影響系統原來自身安裝的 PHP
box get php@8.1
// 透過 box 安裝 composer
box get composer
// 透過 box composer 建立 hyperf 應用,可指定 dev-master 分支以防止 packagist 代理資料落後的問題
box composer create-project hyperf/swow-skeleton:dev-master
// 透過 box 啟動 hyperf
box hyperf start

至此一個完整的安裝和執行流程已完成,我們可以發現過往復雜的環境部署環節,已經簡化為了區區幾個命令,透過 && 連線符甚至可以組成一行命令足以。

透過 Box 打包 Hyperf 應用為二進位制程式

這個神奇的能力,在操作上也被簡化得匪夷所思,只需預先執行 box build-prepare 命令提前下載好相關依賴,這個命令只需執行一次即可,後續即可透過 box build 命令對當前所在資料夾的 Hyperf 應用進行打包動作。打包好後,當前資料夾會出現一個名為 hyperf 的二進位制檔案,後續只需要透過 hyperf start 命令即可啟動該 Hyperf 應用。

Box 自身就是一個基於 Box 打包出來的 Hyperf 應用,大家也可以透過了解 Box 專案本身,來了解該能力的使用。

Box Kernel 切換

預設情況下,Box 由 Swow Kernel 提供支援,但是我們也提供了 Swoole Kernel,您可以透過 box config set kernel swoole 來切換為 Swoole Kernel,但是需要注意的是,Swoole Kernel 僅支援 PHP 8.1 版本,且不支援構建二進位制程式功能和 Windows 系統環境。

// 設定為 Swow Kernel [預設]
box config set kernel swow

// 設定為 Swoole Kernel (不支援 Windows)
box config set kernel swoole

Box 的更多能力

Box 還有更多有意思的使用方法和工具組合,可以透過下面的部分的命令清單快速一覽

命令

box get pkg@version從遠端安裝包,pkg是包名,version是包的版本,box get pkg表示安裝最新版本的 pkg,例如, 執行 box get php@8.1 安裝 PHP 8.1, 執行 box get composer 安裝最新的 composer bin
box build-prepare 為 build 和 build-self 命令做好相關環境的準備
box build-self 構建 box bin 本身
box build <path> 將 Hyperf 應用程式構建成二進位制檔案
box self-update 將 box bin 更新至最新版本
box config set-php-version <version>設定 box 的當前 PHP 版本,可用值:8.0 | 8.1
box config get-php-version <version>獲取 box 的當前設定的 PHP 版本
box reverse-proxy -u <upsteamHost:upstreamPort> 啟動一個反向代理 HTTP 伺服器,用於將 HTTP 請求轉發到指定的多個上游伺服器
box php <argument> 透過當前 box 的 PHP 版本執行任何 PHP 命令
box composer <argument>透過當前 box 的 PHP 版本執行任何 Composer 命令
box php-cs-fixer <argument> 透過當前 box 的 PHP 版本執行任何 php-cs-fixer 命令
box cs-fix <argument> 透過當前 box 的 PHP 版本執行 php-cs-fixer fix 命令
box phpstan <argument> 透過當前 box 的 PHP 版本執行任何 phpstan 命令
box pint <argument> 透過當前 box 的 PHP 版本執行任何 pint 命令

更多最佳化

Hyperf 3.0 仍做了大量的最佳化和調整,具體可以閱讀 Hyperf 主倉庫中的 CHANGELOG-3.0.md 檔案。

同時我們也為大家準備了一份從 2.2 升級至 3.0 的指南,具體可查閱 Hyperf 官方文件 - 3.0 升級指南 一章。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章