Swoole v4.6.0
版本發佈了,一樣也是 2021 年的首個版本更新。php
做爲一個 y 版本發佈,這次更新也包含了不兼容的修改以及許多的新功能,下面就來看一看都有哪些改動?html
v4.6.0
版本開始將再也不支持 PHP7.1
PHP 官方對於 PHP7.1
的支持也早已在 2019 年末結束。react
Event::rshutdown()
標記爲已棄用,請改用 Coroutine\run
在以前的版本中,若是在index.php
中直接使用go
建立協程安全
go(function () { var_dump(Co\System::gethostbyname('www.baidu.com')); });
這樣是正常的,可是在此版本中,就會收到廢棄警告bash
PHP Deprecated: Swoole\Event::rshutdown(): Event::wait() in shutdown function is deprecated in Unknown on line 0
推薦使用Coroutine\run
來代替這種方式:swoole
Swoole\Coroutine\run(function () { var_dump(Co\System::gethostbyname('www.baidu.com')); }); Swoole\Coroutine\run(function () { go(function () { var_dump(Co\System::gethostbyname('www.baidu.com')); }); go(function () { var_dump(Co\System::gethostbyname('www.zhihu.com')); }); });
Coroutine
hook使用了上面所說的Coroutine\run
以後,也會迎來一個新的變動:默認啓用 Coroutine
hook,即自動設置SWOOLE_HOOK_ALL
session
use Swoole\Runtime; Swoole\Coroutine\run(function () { $flags = Runtime::getHookFlags(); assert($flags === SWOOLE_HOOK_ALL); var_dump($flags); });
固然也能夠自行設置所須要的 flag
dom
use Swoole\Runtime; Runtime::setHookFlags(SWOOLE_HOOK_TCP); Swoole\Coroutine\run(function () { $flags = Runtime::getHookFlags(); assert($flags === SWOOLE_HOOK_TCP); var_dump($flags); });
pcntl_fork
/pcntl_wait
/pcntl_waitpid
/pcntl_sigtimedwait
Swoole\Coroutine\run(function () { $pid = pcntl_fork(); var_dump($pid); });
在此版本使用上面的示例代碼,你將會獲得一個 Warning
錯誤curl
PHP Warning: pcntl_fork() has been disabled for security reasons
session_id
的最大限制,再也不重複將 Server 的 session_id
從 int24
改成了 int64
,這樣能夠持續自增,永不重複。socket
以前的int24
時,session_id
大約能夠到 1600 萬就可能會出現重複的問題。
在這個版本中最大的變化莫過於支持了原生 curl
協程客戶端,有什麼用呢?
用過 SWOOLE_HOOK_CURL
的小夥伴應該知道,有一些不支持的選項,同時還會由於部分 SDK 的不兼容致使一些錯誤,例如:
PHP Notice: Object of class Swoole\Curl\Handler could not be converted to int PHP Warning: curl_multi_add_handle() expects parameter 2 to be resource, object given
緣由是 hook 後的 curl
再也不是一個 resource
類型,而是 object
類型。
出現這種問題也建議聯繫 SDK 方修改代碼,由於在PHP8
中curl
再也不是resource
類型,而是object
類型
以及常常使用的阿里雲 OSS SDK 也是不支持SWOOLE_HOOK_CURL
的,會遇到一些奇奇怪怪的
那麼從 v4.6.0
版本開始就可使用 SWOOLE_HOOK_NATIVE_CURL
代替 SWOOLE_HOOK_CURL
,來解決以上提到的問題
使用SWOOLE_HOOK_NATIVE_CURL
須要在編譯 Swoole 擴展時增長 --enable-swoole-curl 編譯參數,開啓該選項後將自動設置 SWOOLE_HOOK_NATIVE_CURL
,關閉 SWOOLE_HOOK_CURL
,同時 SWOOLE_HOOK_ALL
也會包含 SWOOLE_HOOK_NATIVE_CURL
pecl 的 v4.6.0 版本暫時沒有增長這個選項,請使用手動編譯開啓,下個版本中會增長。
編譯成功後使用--ri
查看信息,就能夠看到curl-native
$ php --ri swoole | grep curl curl-native => enabled
從下面的例子就能夠看出二者的不一樣
Swoole\Runtime::setHookFlags(SWOOLE_HOOK_CURL); Swoole\Coroutine\run(function () { $curl = curl_init(); var_dump(get_class($curl), (int) $curl); //PHP Notice: Object of class Swoole\Curl\Handler could not be converted to int //string(19) "Swoole\Curl\Handler" //int(1) });
Swoole\Coroutine\run(function () { $curl = curl_init(); var_dump($curl, (int) $curl); //resource(4) of type (Swoole-Coroutine-cURL Handle) //int(4) });
增長了對 ext-sockets 的協程化支持
const N = 8; $GLOBALS['time'] = []; $s = microtime(true); Swoole\Runtime::setHookFlags(SWOOLE_HOOK_SOCKETS); Swoole\Coroutine\run(function () { $n = N; while($n--) { go(function() { $s = microtime(true); $domain = 'www.baidu.com'; $sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); socket_connect($sock, $domain, 80); socket_write($sock, "GET / HTTP/1.0\r\nHost: $domain\r\nConnection: close\r\nKeep-Alive: off\r\n\r\n"); $html = ''; while(true) { $data = socket_read($sock, 8192); if ($data == '') { break; } $html .= $data; } socket_close($sock); $GLOBALS['time'][] = microtime(true) - $s; }); } }); echo "Done\n"; var_dump(microtime(true) - $s, array_sum($GLOBALS['time']) / 3);
默認不啓用。經過設置 event_object 參數進行啓用,如下事件回調將使用對象風格
以 onConnect
爲例,具體內容可參考文檔 回調對象
$server->on('Connect', function (Swoole\Server $server, int $fd, int $reactorId) { var_dump($fd); }); $server->set([ 'event_object' => true, ]); $server->on('Connect', function (Swoole\Server $serv, Swoole\Server\Event $object) { var_dump($object); });
支持重複設置相同 $key
的 HTTP 頭,而且 $value
支持多種類型,如 array
、object
、int
、float
,底層會進行 toString
轉換,而且會移除末尾的空格以及換行
$http = new Swoole\Http\Server('0.0.0.0', 9501); $http->on('request', function ($request, $response) { $response->header('Test-Value', [ "a\r\n", 'd5678', "e \n ", null, 5678, 3.1415926, ]); $response->header('Foo', new SplFileInfo('bar')); }); $http->start();
$ curl -I http://127.0.0.1:9501 HTTP/1.1 200 OK Test-Value: a Test-Value: d5678 Test-Value: e Test-Value: 5678 Test-Value: 3.1415926 Foo: bar Server: swoole-http-server Connection: keep-alive Content-Type: text/html Date: Wed, 06 Jan 2021 05:16:17 GMT Content-Length: 39
默認開啓,能夠經過在 Coroutine::set 中設置 enable_deadlock_check
進行關閉
在 EventLoop 終止後,若是存在協程死鎖,底層會輸出相關堆棧信息:
=================================================================== [FATAL ERROR]: all coroutines (count: 1) are asleep - deadlock! =================================================================== [Coroutine-2] -------------------------------------------------------------------- #0 Swoole\Coroutine::printBackTrace() called at [@swoole-src/library/core/Coroutine/functions.php:74] #1 Swoole\Coroutine\deadlock_check() #2 curl_getinfo() called at [/mnt/c/code/php/hyperf-skeleton/vendor/aliyuncs/oss-sdk-php/src/OSS/Http/RequestCore.php:492]
下面是完整的更新日誌
session id
的最大限制,再也不重複 (#3879) (@matyhtf)pcntl_fork
/pcntl_wait
/pcntl_waitpid
/pcntl_sigtimedwait
(#3880) (@matyhtf)Event::rshutdown()
標記爲已棄用,請改用 Coroutine\run (#3881) (@matyhtf)port->set()
dtls 編譯錯誤 (#3947) (@Yurunsoft)