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)