Swoole,PHP
git clone https://github.com/Watish/WatishWEBcomposer create-project watish/watishweb:dev-master項目的入口文件為項目/bin/CoServer.php
swoole-cli ./bin/CoServer.php php ./bin/CoServer.php
在src/Controller目錄下新建一個類,這裡我們定義為HelloController
<?php
namespace Watish WatishWEB Controller ;
use Watish Components Attribute Path ;
use Watish Components Struct Request ;
class HelloController
{
#[Path( ' / ' )]
public function index ( Request $ request ) : array
{
return [
" msg " => " hello world "
];
}
}保存後,啟動項目,訪問http://127.0.0.1:9502/ 便能看到
{ "msg" : " hello world " }是不是很簡單?
不同於傳統的php-fpm形式,多進程之間存在內存隔離,這意味著在進程A設定的變量進程B是無法獲取的,此外,請求與請求之間並不是隔離的,也就是說,在同一進程下的兩個請求,儘管在不同的協程中處理邏輯,如果都對全局變量A修改,那麼全局變量會被修改兩次
具體可查閱swoole文檔中的編程須知#嚴重錯誤
使用WatishComponentsIncludesContext可以有效規避上述問題
Context是一個靜態類,不僅提供了簡單的Get , Set方法,還通過進程通信提供了多worker進程全局變量的GlobalSet,GlobalGet等方法
注:多worker進程全局變量設定(Context::Global_Set等方法)是基於UnixSocket異步實現的,不能保證某一時刻的數據一致,這裡可以使用WatishComponentsUtilsTable ,一個對SwooleTable的封裝KV內存表,可以充分利用每一行資源,並支持閉包序列化
當瀏覽器發送請求至服務器,服務器會調用handle方法,隨後通過路由調度器判斷請求路由是否存在,存在解析路由參數,封裝至WatishComponentsStructRequest ,傳入全局中間件-> 局部中間件-> 控制器
註冊路由的兩種方式
注:需要在**/config/server.php **中修改**register_route_auto **為true
. . .
" register_route_auto " => true
...Prefix是類註解,定義該類下路由的前綴
#[Prefix(string $ prefix )]Path是方法註解,定義路由路徑
#[Path(string $ path ,array $ methods )]舉個栗子:
<?php
namespace Watish WatishWEB Controller ;
use Watish Components Attribute Middleware ;
use Watish Components Attribute Path ;
use Watish Components Attribute Prefix ;
use Watish Components Struct Request ;
use Watish WatishWEB Middleware TestMiddleware ;
#[Prefix( ' /hello ' )]
class HelloController
{
#[Path( ' /index ' )]
public function index ( Request $ request ) : array
{
return [
" msg " => " hello world "
];
}
#[Path( ' /user/{name} ' ,[ ' GET ' , ' POST ' ])]
#[Middleware([TestMiddleware::class])]
public function msg ( Request $ request ) : array
{
return [
" msg " => " hello " . $ request -> route ( ' name ' )
];
}
}上述代碼的路由如下
| 路徑 | 控制器 | 方法 | 中介軟體 |
|---|---|---|---|
| /hello/index | HelloController@index | ANY | 無 |
| /hello/user/{name} | HelloController@msg | GET,POST | TestMiddleware |
路由配置文件路徑為:項目/config/route.php
復用上面的栗子,則上述路由配置應如下
<?php
use Watish Components Includes Route ;
use Watish WatishWEB Controller HelloController ;
function do_register_global_middleware ( Route $ route ): void
{
/**
$route->register_global_middleware(CorsMiddleware::class);
*/
}
function do_register_routes ( Route $ route ): void
{
$ route -> register ( ' /hello/index ' ,[HelloController::class, ' index ' ],[],[]);
$ route -> register ( ' /hello/user/{name} ' ,[HelloController::class, ' msg ' ],[TestMiddleware: class ],[ ' GET ' , ' POST ' ]);
}register方法傳參如下
Watish Components Includes Route-> register (string $ path , array $ callback , array $ before_middlewares , array $ methods )注:中間件都要implement MiddlewareInterface接口
通過註解註冊
可以通過使用GlobalMiddleware的類註解實現全局中間件的註冊
舉個例子:
<?php
namespace Watish WatishWEB Middleware ;
use Watish Components Attribute GlobalMiddleware ;
use Watish Components Struct Request ;
use Watish Components Struct Response ;
#[GlobalMiddleware]
class CorsMiddleware implements MiddlewareInterface
{
public function handle ( Request $ request , Response $ response ): void
{
$ response -> header ( " Access-Control-Allow-Origin " , " * " );
$ response -> header ( " Access-Control-Allow-Credentials " , true );
}
}通過路由註冊
配置文件路徑為:項目/config/route.php
<?php
use Watish Components Includes Route ;
use Watish WatishWEB Controller HelloController ;
use Watish WatishWEB Middleware CorsMiddleware ;
function do_register_global_middleware ( Route $ route ): void
{
$ route -> register_global_middleware (CorsMiddleware::class);
}
function do_register_routes ( Route $ route ): void
{
$ route -> register ( ' /hello/index ' ,[HelloController::class, ' index ' ],[],[]);
$ route -> register ( ' /hello/user/{name} ' ,[HelloController::class, ' msg ' ],[],[ ' GET ' , ' POST ' ]);
}通過註解註冊
可以使用Middleware來對控制器或者某個方法進行註解
#[Middleware(array $ middlewares )]先創建一個TestMiddleware
<?php
namespace Watish WatishWEB Middleware ;
use Watish Components Struct Request ;
use Watish Components Struct Response ;
class TestMiddleware implements MiddlewareInterface
{
public function handle ( Request $ request , Response $ response )
{
$ response -> header ( " test " , " test " );
}
}然後修改HelloController
<?php
namespace Watish WatishWEB Controller ;
use Watish Components Attribute Middleware ;
use Watish Components Attribute Path ;
use Watish Components Attribute Prefix ;
use Watish Components Struct Request ;
use Watish WatishWEB Middleware TestMiddleware ;
#[Prefix( ' /hello ' )]
class HelloController
{
#[Path( ' /index ' )]
#[Middleware([TestMiddleware::class])]
public function index ( Request $ request ) : array
{
return [
" msg " => " hello world "
];
}
#[Path( ' /user/{name} ' ,[ ' GET ' , ' POST ' ])]
#[Middleware([TestMiddleware::class])]
public function msg ( Request $ request ) : array
{
return [
" msg " => " hello " . $ request -> route ( ' name ' )
];
}
}如上,index方法和msg方法都有了局部中間件TestMiddleware
當然,上述代碼還能一下這樣寫,直接給HelloController添加Middleware註解
<?php
namespace Watish WatishWEB Controller ;
use Watish Components Attribute Middleware ;
use Watish Components Attribute Path ;
use Watish Components Attribute Prefix ;
use Watish Components Struct Request ;
use Watish WatishWEB Middleware TestMiddleware ;
#[Prefix( ' /hello ' )]
#[Middleware([TestMiddleware::class])]
class HelloController
{
#[Path( ' /index ' )]
public function index ( Request $ request ) : array
{
return [
" msg " => " hello world "
];
}
#[Path( ' /user/{name} ' ,[ ' GET ' , ' POST ' ])]
public function msg ( Request $ request ) : array
{
return [
" msg " => " hello " . $ request -> route ( ' name ' )
];
}
}通過配置文件註冊
參考路由章節中的配置文件路由註冊方法register 傳參,此處不做贅述
控制器是整個業務項目的核心,負責處理請求,調用服務,返回數據
比較簡單,不多描述
配合依賴注入,舉個栗子:
<?php
namespace Watish WatishWEB Controller ;
use Watish Components Attribute Inject ;
use Watish Components Attribute Middleware ;
use Watish Components Attribute Path ;
use Watish Components Attribute Prefix ;
use Watish Components Struct Request ;
use Watish WatishWEB Middleware TestMiddleware ;
use Watish WatishWEB Service BaseService ;
#[Prefix( ' /hello ' )]
#[Middleware([TestMiddleware::class])]
class HelloController
{
#[Inject(BaseService::class)]
public BaseService $ baseService ;
#[Path( ' /index ' )]
public function index ( Request $ request ) : array
{
return [
" msg " => $ this -> baseService -> toArray ([ " Hello " , ' World ' ])
];
}
#[Path( ' /user/{name} ' ,[ ' GET ' , ' POST ' ])]
public function msg ( Request $ request ) : array
{
return [
" msg " => " hello " . $ request -> route ( ' name ' )
];
}
}注:暫不支持構造方法注入,後續會完善(挖坑)
直接貼代碼
<?php
namespace Watish WatishWEB Service ;
use Watish Components Attribute Async ;
use Watish Components Attribute Inject ;
use Watish Components Utils Logger ;
class TestService
{
#[Inject(BaseService::class)]
public BaseService $ baseService ;
#[Async]
public function asyncHello (): void
{
Logger:: info ( " Hello " );
}
public function hello ( string $ name ) : string
{
return " hello { $ name }" ;
}
}在Service中,仍然可以進行依賴注入,此外,還可以對方法進行Async註解(注意,被Async註解的方法必須是void類型)使其成為一個異步方法
Command類文件存放於項目/src/Command/
注:Command類需要implement CommandInterface 接口
命令類只能使用註解註冊命令
示例代碼如下:
<?php
namespace Watish WatishWEB Command ;
use Watish Components Attribute Command ;
use Watish Components Utils Logger ;
#[Command( " hello " , " command " )]
class HelloCommand implements CommandInterface
{
public function handle (): void
{
Logger:: info ( " Hello " );
}
}上述代碼,可以通過以下方式執行
swoole-cli
swoole-cli ./bin/CoServer.php command:helloPHP
php ./bin/CoServer.php command:hello
註解Command的用法
Command (string $ command , string $ prefix = " command " )Task類存放於項目/src/Task/
注:所有的Task類都要implement TaskInterface
Task類只支持使用Crontab註解註冊定時任務
示例代碼如下:
<?php
namespace Watish WatishWEB Task ;
use Watish Components Attribute Crontab ;
use Watish Components Utils Logger ;
#[Crontab( " * * * * * " )]
class HelloTask implements TaskInterface
{
public function execute (): void
{
Logger:: info ( " Hello " , " HelloTask " );
}
}這是一個每秒都會輸出Hello的定時任務
Crontab註解使用方法
Crontab (string $ rule )其中,rule為標準的crontab表達式
注:暫只有mysql,redis(可自己加)
本框架使用了連接池來維護mysql,redis連接,並於啟動初完成了連接池的創建,現只需在業務邏輯中使用即可
**WatishComponentsIncludesDatabase::mysql() ** 返回一個對Laravel查詢構造器的封裝(主要是改變了底層Pdo邏輯,正常使用無差異)
WatishComponentsIncludesDatabase::redis()返回一個Predis的Client
請先配置數據庫!配置文件:項目/config/database.php
框架使用了以下組件,並對某些組件進行了封裝
在WatishComponentsConstructor命名空間下,提供了對一些組件的快速構造
AsyncTaskConstructor::make()異步任務投遞
LocalFilesystemConstructor::getFilesystem()本地文件系統構造器
ValidatorConstructor::make(array $data , array $rules) Validator構造器
感謝優秀的組件開發者
測試環境:Ubuntu22.0.4 LTS
測試硬件:虛擬機(VirtualBox) 6c6t , 8192M ,開啟虛擬化支持
測試工具:ApacheBench
This is ApacheBench, Version 2.3 <$Revision: 1879490 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 127.0.0.1 (be patient)
Server Software: swoole-http-server
Server Hostname: 127.0.0.1
Server Port: 9502
Document Path: /hello/user/test
Document Length: 20 bytes
Concurrency Level: 3000
Time taken for tests: 2.040 seconds
Complete requests: 30000
Failed requests: 0
Total transferred: 7680000 bytes
HTML transferred: 600000 bytes
Requests per second: 14708.19 [#/sec] (mean)
Time per request: 203.968 [ms] (mean)
Time per request: 0.068 [ms] (mean, across all concurrent requests)
Transfer rate: 3677.05 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 83 17.3 85 125
Processing: 32 109 41.6 102 380
Waiting: 0 79 40.0 71 362
Total: 107 193 37.8 189 457
Percentage of the requests served within a certain time (ms)
50% 189
66% 200
75% 205
80% 208
90% 224
95% 236
98% 344
99% 389
100% 457 (longest request)
注:不要太在意性能,真正的業務邏輯往往是複雜的,對demo進行壓測並不能表明什麼(圖個樂)
如果好用可以點個star,如果有問題請提issue,作者會積極維護
更新於2022-12-28 16:01
請先運行一遍composer install