Major Changes in Swoole 6.1.0
1. Introduction of "Standard Library Extensions" - Revolutionary Syntax Enhancements
This is the most eye-catching feature at the language level in this update, allowing object-oriented operations on basic types.
- Object-Oriented Basic Types: Methods can be called directly on variables of basic types like
string,array, andstream(e.g.,$text->length()->lower()), greatly improving code readability and development experience. - Typed Arrays: Introduced the
typed_arraysyntax, allowing constraints on key and value types (e.g.,<int, string>), with type checks performed on write operations, enhancing code robustness.
2. A Major Leap in Underlying Architecture and Stability
This version invests heavily in code quality and stability, laying a solid foundation for future development.
- Significant Increase in Test Coverage to 86%: By systematically adding test cases, potential errors are greatly reduced, improving the overall reliability and maintainability of the project.
- Large-Scale Code Refactoring and Static Analysis: Refactored multiple core modules like Reactor, SSL, and Socket, and used
clang-tidyfor code standardization, significantly improving code quality and performance.
3. Major Simplification and Unification of the Lock API
A groundbreaking refactoring of the core component for concurrent programming – the lock.
- API Simplification: Removed methods like
lockwaitandtrylock, retaining only three core methods –__construct,lock, andunlock– forSwoole\Coroutine\Lock,Swoole\Lock, andSwoole\Thread\Lock. - Unified Behavior: The new API design is closer to PHP's native
flockfunction, reducing the learning curve, and uses standard constants likeLOCK_EX | LOCK_NBto implement advanced features such as non-blocking.
4. Enhanced Coroutine Capabilities and Fine-Grained Control
More flexible coroutine operation capabilities.
- Coroutine Cancellation Mechanism:
Swoole\Coroutine::cancel()now includes a$throw_exceptionparameter, allowing a catchableSwoole\Coroutine\CanceledExceptionto be thrown into the target coroutine upon cancellation, enabling safer and more controllable coroutine lifecycle management. - Coroutine State Isolation for Serialization Operations: Fixed the issue of global state isolation for serialize/unserialize in coroutine environments. Global variables related to serialization are now automatically saved and restored during coroutine switches, ensuring isolated serialization contexts for each coroutine.
5. Default HTTP Parser Upgrade, Websocket Feature Enhancements, and Platform Compatibility Improvements
Important improvements in performance and compatibility.
- llHTTP Enabled by Default: Replaced the old
http_parserwith the more performant and modernllhttp, improving the efficiency and reliability of HTTP processing. - WebSocket Feature Enhancements: Both client and server now support receiving fragmented messages, actively disconnecting (
disconnect), and sending Ping frames (ping), making the WebSocket protocol implementation more complete. - Deprecating Select, Embracing Poll: Completely deprecated the flawed
selectevent mechanism. On platforms that do not supportepoll/kqueue(like Cygwin),pollis now used by default, enabling support for a large number of concurrent connections on these platforms as well.
🎉 Standard Library Extensions
Swoole-Cli version 6.1 will add PHP standard library extension syntax, providing some additional new syntax while maintaining full compatibility with the official PHP syntax. These new extension syntaxes are all optional and do not affect existing PHP code. The standard library extension syntax will be implemented in the stdext module of ext-swoole.
swoole-cliusers can use it directly without any additional parameters.ext-swooleusers need to add--enable-swoole-stdextduring compilation to enable it.stdextcan be used inphp-cli,php-fpm,cli-http-server, andswoolemodes.
1. Object-Oriented Basic Types
Version 6.1 implements object-oriented encapsulation of array, string, and stream basic types, supporting method calls in an object-oriented style. Methods can be called directly on variables of these types.
The built-in methods for basic types actually still call the PHP standard library implementations. There is a one-to-one correspondence between the built-in methods and PHP's str_ or array_ series of functions. For example, $text->replace() corresponds to the str_replace function. The underlying layer only adjusts the function names, the parameter order for a few methods, and the parameter and return value types for a couple of methods. Please refer to the Swoole Documentation for details.
$text = 'Hello Swoole';
var_dump($text->length());
echo $text->lower()->replace("swoole", "php");
echo fopen("/tmp/test.log")->read(1024);2. Typed-Array Strongly Typed Arrays
Allows restricting array types, such as Map or ArrayList, and restricting the types of key and value. Supports multi-level nested formats. A typed array is still essentially an array type; the underlying layer only performs parameter checks on write operations. A typed array can be passed as an array to other functions or class methods.
$array = typed_array('<int, string>');
$array[1000] = "hello"; // Correct
$array[2000] = 2025; // Error, throws an exception✨ New Features
- llHTTP Default Parser: Starting from v6.1.0, Swoole uses the more performant
llhttpinstead ofhttp_parseras the default HTTP message parser. - Coroutine-based File Download:
Swoole\Coroutine\Http\Clientnow supports complete coroutine-based file download operations. - Asynchronous File Truncation: Added
iouring ftruncatesupport, expanding asynchronous file operation capabilities. Swoole\Coroutine::cancel()adds a$throw_exceptionparameter, supporting throwing an exception when canceling a coroutine.Swoole\Coroutine\Http\ClientandSwoole\Coroutine\Http\Servernow support receiving WebSocket fragmented messages.- Added
disconnectandpingmethods forSwoole\Coroutine\Http\ClientandSwoole\Coroutine\Http\Server. - Refactored
Swoole\Coroutine\Lock,Swoole\Lock, andSwoole\Thread\Lock, retaining only the__construct,lock, andunlockmethods, making usage closer tophp flock.
🐛 Bug Fixes
- Thread Mode Optimization:
- Fixed the issue where
hook_flagssettings became ineffective inSWOOLE_THREADmode. - Fixed the issue where the heartbeat thread held invalid pointers and accessed freed memory after worker threads restarted due to reaching the
max_requestlimit. - Fixed the issue of not supporting restarting
Taskprocesses individually. - Fixed an issue where
Swoole\Websocket\Servermight still trigger theonMessagecallback after a handshake failure or connection closure. - Fixed execution errors in
Swoole\Coroutine\Http\Servercaused by inconsistencies between function return value types and signatures. - Fixed the issue where
Swoole\Coroutine\Http\Serverdid not support enabling HTTP/2. - Fixed the timeout precision conversion issue in
Swoole\Lock::lockwait(). - Fixed the issue causing
ReactorEpoll::add(): failed to add eventwarnings when using the coroutine-basedcurlmodule, due toPHP 8compatibility adjustments and incomplete cleanup ofkeepaliveconnections. - Fixed the issue where
Swoole\Server::taskWaitMulti()could not be used in multi-threaded mode. - Fixed resource competition issues in
Swoole\Server::taskCo()in multi-threaded mode.
- Fixed the issue where
- Stability Improvements:
- Fixed the issue where synchronous processes (including manager and task processes) could not normally use
process::signal(). - Corrected the resource cleanup mechanism when worker processes exit abnormally.
- Resolved compilation failure issues on the Cygwin platform.
- Fixed the issue where curl with keepalive enabled could not reuse sockets.
- Improved the log component to resolve data consistency issues in multi-threaded mode.
- Fixed the compilation failure of the
io_uringfutexfeature onubuntu24.04. - Fixed the compilation failure on older Linux systems due to struct order assignment.
- Fixed the uninitialized
idproperty issue for directly instantiatedSwoole\Processobjects. - Fixed the missing
--enable-zstdoption in composer.json when compiling swoole withPIE. - Fixed the issue where
workerprocesses could not send signals to themanagerprocess due to insufficient permissions after specifying a user group.
- Fixed the issue where synchronous processes (including manager and task processes) could not normally use
- Compatibility Improvements:
- Fixed compatibility issues with
php_swoole_register_shutdown_functionunder PHP 8.5. - Corrected the handling of null parameters in
Swoole\Table::get().
- Fixed compatibility issues with
- Protocol Handling:
- Optimized the handling mechanism for duplicate fields in HTTP request and response headers to ensure correct merging.
- Fixed the issue where processing a client
Accept-Encoding: zlibrequest header would trigger an unknown compression method warning when the system lackedzlib.
❌️ Deprecations
- No longer supports the
selectevent mechanism.selectonly supports event monitoring for up to1024file descriptors and has serious flaws. On platforms that do not supportepoll/kqueue,pollwill be used as the event polling mechanism, allowing theCygwinplatform to also support a large number of concurrent connections. - In the
Swoole\Server::stop()method, the second parameter$waitEventhas been deprecated; please use thereload_asyncparameter instead.
🛠️ Architectural Optimizations
Version 6.1 adds a large number of unit tests for core modules, increasing test coverage to 86%. By systematically supplementing test cases and refactoring underlying code logic, combined with full static code analysis using the clang-tidy toolchain, automated code formatting and redundancy cleanup have been achieved, significantly improving code readability and maintainability.
- Optimized the underlying
SSLmodule. - Optimized the underlying
Socketmodule. - Refactored the underlying synchronous signal module.
- Refactored the underlying
reactorandstringmodules. - Refactored the underlying dynamic reloading of log files based on
SIGRTMINsignals. - Optimized the underlying static file server, removing C-style code and unifying it into C++ style code.
- Optimized thread initialization logic, improved multi-threading performance, independently managed structure memory, eliminating the need for locking during thread creation and exit.
- Removed the
socket_dontwaitoption in the underlyingasyncmodule, as it was deprecated. - Improved test coverage for
WebSocketmask handling. - Optimized the
sendfilefunctionality; thetcp_corkoption is not set when the file is smaller than64KB. - Added unit tests for
aarch64andmacOSenvironments. - Optimized underlying client network address resolution and settings.
- Added
ssl_cafile/ssl_capathconfiguration items for theServermodule. - Added the
print_backtrace_on_errorconfiguration, which can print C function stack traces when unknown errors occur. - Added the
Address Sanitizerdebugging tool. - Added
Cygwintesting, significantly improving compatibility and stability on theCygwinplatform. - In
macOSsystems, because thekqueueevent mechanism does not support cross-process pipe event monitoring, it is impossible to useSWOOLE_PROCESSmode andTaskprocess features. Therefore, the system will default to usingpollas the underlying event mechanism. If you need to enablekqueue, you can manually enable it via theSwoole\Server::set(['enable_kqueue' => true])andswoole_async_set(['enable_kqueue' => true])methods. - Upgraded the
Swoole libraryversion. - Disabled the
-Wdate-timewarning to resolve errors when compiling with Zig/Clang. - Removed PHP 8.0 related compatibility code.
- Added the
SWOOLE_ODBC_LIBSvariable inconfig.m4. - Ensured that
timespec.tv_nsecvalues are less than1,000,000,000to comply with POSIX standard specifications. - Refactored the underlying code for
swoolecoroutine-basedcurlto improve compatibility with the synchronous blocking version.
⚠️ Notes
- Starting from Swoole 6.1,
Swoole\Coroutine\Http\ClientandSwoole\Coroutine\Http\Serverwill automatically handle WebSocket control frames unlessopen_websocket_ping_frame,open_websocket_pong_frame, oropen_websocket_close_frameare explicitly set. Swoole\Coroutine::cancel()cannot cancel file coroutine operations; forcing cancellation may cause segmentation faults.- If
--enable-iouringis enabled, a warning will be thrown if the kernel version orliburingversion does not meet the requirements. - The
Swoole\Websocket\Server::pushmethod does not automatically close the connection after sending a close frame. To close the connection, please use theSwoole\Websocket\Server::disconnect()method. - When processing control frames, the
Swooleprotocol actively sets the FIN flag to 1 and ensures compression is not enabled (i.e., the RSV1 bit is 0). User settings for this will be ignored. - When handling compression and sending of consecutive frames,
Swooledelegates the responsibility of compression and data chunking to the application layer. Users need to manually implement the relevant logic. See the example at the end. - The system has automatically enabled the
HTTP 100 Continueresponse feature by default. - During coroutine switches, global variables related to
serializeandunsealizeoperations will be saved and restored.
💡 API Changes
New Lock API
Function Prototypes
namespace Swoole\Coroutine {
class Lock {
public function __construct(bool $shared = false) {}
public function lock(int $operation = LOCK_EX): bool {}
public function unlock(): bool {}
}
}
namespace Swoole {
class Lock {
public function __construct(int $type = SWOOLE_MUTEX) {}
public function lock(int $operation = LOCK_EX, float $timeout = -1): bool {}
public function unlock(): bool {}
}
}
namespace Swoole\Thread {
class Lock {
public function __construct(int $type = SWOOLE_MUTEX) {}
public function lock(int $operation = LOCK_EX, float $timeout = -1): bool {}
public function unlock(): bool {}
}
}Usage Example
$lock = new Swoole\Lock;
$lock->lock(LOCK_EX | LOCK_NB, 0.5);
$lock->unlock();Canceling a Coroutine
Co\run(function () {
$cid = Co\go(function () {
try {
while (true) {
System::sleep(0.1);
echo "co 2 running\n";
}
var_dump('end');
} catch (Swoole\Coroutine\CanceledException $e) {
var_dump('cancelled');
}
});
System::sleep(0.3);
Co::cancel($cid, true);
System::sleep(0.2);
echo "co 1 end\n";
});WebSocket Compression and Sending Consecutive Frames
Asynchronous Server
use Swoole\WebSocket\Server;
use Swoole\WebSocket\Frame;
$server = Server('127.0.0.1', 9502);
$server->set(['websocket_compression' => true]);
$server->on('message', function (Server $server, Frame $frame) {
$data1 = bin2hex(random_bytes(10 * 1024));
$data2 = bin2hex(random_bytes(20 * 2048));
$data3 = bin2hex(random_bytes(40 * 4096));
$context = deflate_init(ZLIB_ENCODING_RAW); // Stream compression
$server->push($frame->fd, deflate_add($context, $data1, ZLIB_NO_FLUSH), SWOOLE_WEBSOCKET_OPCODE_TEXT, SWOOLE_WEBSOCKET_FLAG_COMPRESS | SWOOLE_WEBSOCKET_FLAG_RSV1);
$server->push($frame->fd, deflate_add($context, $data2, ZLIB_NO_FLUSH), SWOOLE_WEBSOCKET_OPCODE_CONTINUATION, 0);
$server->push($frame->fd, deflate_add($context, $data3, ZLIB_FINISH), SWOOLE_WEBSOCKET_OPCODE_CONTINUATION, SWOOLE_WEBSOCKET_FLAG_FIN);
});
$server->start();Coroutine Server
use function Swoole\Coroutine\run;
use Swoole\Coroutine\Http\Server;
run(function() {
$server = new Server("127.0.0.1", 9502);
$server->set(['websocket_compression' => true]);
$server->handle('/', function ($request, $response) use ($data1, $data2, $data3) {
$response->upgrade();
$data1 = bin2hex(random_bytes(10 * 1024));
$data2 = bin2hex(random_bytes(20 * 2048));
$data3 = bin2hex(random_bytes(40 * 4096));
$context = deflate_init(ZLIB_ENCODING_RAW);
$response->push(deflate_add($context, $data1, ZLIB_NO_FLUSH), SWOOLE_WEBSOCKET_OPCODE_TEXT, SWOOLE_WEBSOCKET_FLAG_COMPRESS | SWOOLE_WEBSOCKET_FLAG_RSV1);
$response->push(deflate_add($context, $data2, ZLIB_NO_FLUSH), SWOOLE_WEBSOCKET_OPCODE_CONTINUATION, 0);
$response->push(deflate_add($context, $data3, ZLIB_FINISH), SWOOLE_WEBSOCKET_OPCODE_CONTINUATION, SWOOLE_WEBSOCKET_FLAG_FIN);
});
});Coroutine Client
use function Swoole\Coroutine\run;
use Swoole\Coroutine\Http\Client;
run(function() {
$client = new Client('127.0.0.1', 9502);
$client->set(['websocket_compression' => true]);
$ret = $client->upgrade('/');
$context = deflate_init(ZLIB_ENCODING_RAW);
$client->push(deflate_add($context, $data1, ZLIB_NO_FLUSH), SWOOLE_WEBSOCKET_OPCODE_TEXT, SWOOLE_WEBSOCKET_FLAG_COMPRESS | SWOOLE_WEBSOCKET_FLAG_RSV1);
$client->push(deflate_add($context, $data2, ZLIB_NO_FLUSH), SWOOLE_WEBSOCKET_OPCODE_CONTINUATION, 0);
$client->push(deflate_add($context, $data3, ZLIB_FINISH), SWOOLE_WEBSOCKET_OPCODE_CONTINUATION, SWOOLE_WEBSOCKET_FLAG_FIN);
});🙏 Thank You
Sincere thanks to @matyhtf @jingjingxyk @sy-records @KIMDONGYEON00 @ServBayDev @Appla @henderkes @NathanFreeman and all contributors for your professional dedication. Swoole is more powerful because of you! Wishing all friends in the open-source community good health, success in all your endeavors, and smooth work.
Swoole 6.1.0 最大的几个变更
1. 引入“标准库扩展” - 革命性的语法增强
这是本次更新在语言层面最引人注目的特性,它允许以面向对象的方式操作基础类型。
- 基础类型对象化:可以直接对
string、array、stream等基础类型的变量调用方法(如$text->length()->lower()),这极大地提升了代码的可读性和编写体验。 - 强类型数组:引入了
typed_array语法,可以定义键值类型的约束(如<int, string>),在写入时进行类型检查,增强了代码的健壮性。
2. 底层架构与稳定性的巨大飞跃
本次版本在代码质量和稳定性上投入巨大,为未来的发展奠定了坚实基础。
- 测试覆盖率大幅提升至86%:通过系统性地补充测试用例,极大地减少了潜在的错误,提高了整个项目的可靠性和可维护性。
- 大规模代码重构与静态分析:重构了 Reactor、SSL、Socket 等多个核心模块,并使用
clang-tidy进行代码规整,显著提升了代码质量和性能。
3. 锁 API 的重大简化与统一
对并发编程的核心组件——锁,进行了颠覆性的重构。
- API 精简:移除了
lockwait、trylock等方法,只为Swoole\Coroutine\Lock、Swoole\Lock和Swoole\Thread\Lock保留__construct、lock和unlock三个核心方法。 - 行为统一:新的 API 设计更贴近 PHP 原生的
flock函数,降低了学习成本,并使用LOCK_EX | LOCK_NB等标准常量来实现非阻塞等高级功能。
4. 协程能力的强化与精细化控制
更加灵活的协程操作能力。
- 协程取消机制:
Swoole\Coroutine::cancel()新增$throw_exception参数,允许在取消协程时向目标协程内抛出一个可捕获的Swoole\Coroutine\CanceledException,实现了更安全、更可控的协程生命周期管理。 - 实现序列化操作的协程状态隔离:修复协程环境下 serialize/unserialize 的全局状态隔离问题。现已在协程切换时自动保存和恢复相关全局变量,确保各协程序列化上下文互不干扰。
5. 默认 HTTP 解析器升级,Websocket功能增强和平台兼容性改进
在性能和兼容性方面的重要提升。
- 默认启用 llHTTP:用性能更优、更现代的
llhttp替代了旧的http_parser,提升了 HTTP 处理的效率和可靠性。 - WebSocket 功能增强:客户端和服务端均支持了接收分块消息、主动断开连接(
disconnect)和发送 Ping 帧(ping)等能力,使 WebSocket 协议的实现更加完整。 - 废弃 Select,拥抱 Poll:彻底废弃了有严重缺陷的
select事件机制,在不支持epoll/kqueue的平台上(如 Cygwin)默认使用poll,从而在这些平台上也能支持大量并发连接。
🎉 标准库扩展
6.1 版本 Swoole-Cli 将增加 PHP 标准库扩展语法,在保持对 PHP 官方语法完整兼容的同时,提供一些额外的新语法。这些新的扩展语法均是可选的,不影响现有的PHP代码。标准库扩展语法将在ext-swoole的stdext模块中实现。
swoole-cli用户,可直接使用,无需设置任何额外的参数ext-swoole的用户,需在编译时添加--enable-swoole-stdext来启用stdext在php-cli、php-fpm、cli-http-server、swoole模式均可使用
1. 基础类型对象化
6.1 版本实现了array/string/stream基础类型的对象化封装,支持面向对象风格的方法调用,可直接对这些类型的变量调用内置方法。
基础类型的内置方法实际上仍然是调用PHP标准库实现的,内置方法与PHP的str_或array_系列函数是一一对应关系,例如$text->replace()对应的函数是str_replace。底层仅调整了函数名称,少量方法调整了参数顺序,还有几个方法调整了参数和返回值类型,详情请查看 Swoole 文档。
$text = 'Hello Swoole';
var_dump($text->length());
echo $text->lower()->replace("swoole", "php");
echo fopen("/tmp/test.log")->read(1024);2. Typed-Array 强类型数组
可限制数组类型,如:Map或ArrayList,以及限制key与value的类型。支持多层嵌套格式。typed array实际上依然是array类型,底层仅在写入时进行参数检查。typed array可作为array传递给其他函数或类方法。
$array = typed_array('<int, string>');
$array[1000] = "hello"; // 正确
$array[2000] = 2025; // 错误,抛出异常✨ 新特性
- llHTTP 默认解析器:自 v6.1.0 起,Swoole 采用性能更优的
llhttp替代http_parser作为默认 HTTP 报文解析器。 - 协程化文件下载:
Swoole\Coroutine\Http\Client现支持完整的协程化文件下载操作。 - 异步文件截断:新增
iouring ftruncate支持,扩展异步文件操作能力。 Swoole\Coroutine::cancel()新增$throw_exception参数,支持在取消协程时抛出异常。Swoole\Coroutine\Http\Client与Swoole\Coroutine\Http\Server现已支持接收 WebSocket 分块消息。- 为
Swoole\Coroutine\Http\Client和Swoole\Coroutine\Http\Server新增disconnect与ping方法。 - 重构
Swoole\Coroutine\Lock,Swoole\Lock和,Swoole\Thread\Lock,只保留__construct,lock和unlock方法,使用上更加贴近php flock。
🐛 Bug 修复
- 线程模式优化:
- 修复
SWOOLE_THREAD模式下hook_flags设置失效问题。 - 修复因工作线程达到
max_request限制重启后,导致心跳线程持有失效指针并访问已释放内存的问题。 - 修复不支持单独重启
Task进程的问题。 - 修复
Swoole\Websocket\Server在握手失败或连接关闭后,仍可能触发onMessage回调的问题。 - 修复
Swoole\Coroutine\Http\Server因函数返回值类型与签名不一致导致的执行错误。 - 修复
Swoole\Coroutine\Http\Server不支持启用 HTTP/2 的问题。 - 修复
Swoole\Lock::lockwait()超时时间精度转换问题。 - 修复因
PHP 8兼容性调整及keepalive连接清理不彻底,导致使用协程化curl模块时出现ReactorEpoll::add(): failed to add event警告的问题。 - 修复
Swoole\Server::taskWaitMulti()在多线程模式下无法使用的问题。 - 修复
Swoole\Server::taskCo()在多线程模式下资源竞争问题。
- 修复
- 稳定性提升:
- 修复同步进程(含 manager 进程和 task 进程)无法正常使用
process::signal()的问题。 - 修正工作进程异常退出时的资源清理机制。
- 解决 Cygwin 平台编译失败问题。
- 修复curl开启keepalive无法复用socket的问题。
- 改进日志组件以解决多线程模式下的数据一致性问题。
- 修复
io_uring的futex特性在ubuntu24.04编译失败的问题。 - 修复结构体顺序赋值在低版本的linux系统会编译失败的问题。
- 修复直接实例化的
Swoole\Process对象其id属性未初始化的问题。 - 修复使用
PIE编译swoole时,composer.json文件缺少--enable-zstd的选项的问题。 - 修复了指定用户组后,
worker进程因权限不足而无法向manager进程发送信号的问题。
- 修复同步进程(含 manager 进程和 task 进程)无法正常使用
- 兼容性改进:
- 修复 PHP 8.5 下
php_swoole_register_shutdown_function兼容性问题。 - 修正
Swoole\Table::get()对 null 参数的处理。
- 修复 PHP 8.5 下
- 协议处理:
- 优化
HTTP请求头与响应头中重复字段的处理机制,确保其正确合并。 - 修复当系统没有
zlib时,处理客户端Accept-Encoding: zlib请求头会触发未知压缩方法警告的问题。
- 优化
❌️ 废弃
- 不再支持
select事件机制,select仅支持1024个句柄的事件监听,存在严重缺陷,在不支持epoll/kqueue的平台将使用poll作为事件轮训机制,这使得Cygwin平台下也可以支持大量并发。 - 在
Swoole\Server::stop()方法中,第二个参数$waitEvent已被废弃,请使用reload_async参数。
🛠️ 架构优化
6.1版本增加了大量核心模块的单元测试,测试覆盖率提升至86%。通过系统性地补充测试用例并重构底层代码逻辑,同时结合clang-tidy工具链开展全量静态代码分析,实现了代码的自动化格式规整与冗余清理,使得代码可读性与可维护性得到显著提升。
- 优化底层
SSL模块。 - 优化底层
Socket模块。 - 重构底层同步信号模块。
- 重构底层
reactor和string模块。 - 重构底层基于
SIGRTMIN信号实现日志文件动态重载。 - 优化底层静态文件服务器,移除C风格代码,统一为C++风格的代码。
- 优化线程初始化逻辑,提高多线程性能,独立管理结构内存,线程创建和退出不需要再加锁。
- 移除底层
async模块中的socket_dontwait选项,该选项已废弃。 - 完善
WebSocket掩码处理的测试覆盖。 - 优化
sendfile功能,当文件小于64KB时不设置tcp_cork选项。 - 增加
aarch64和macOS环境下的单元测试。 - 优化底层客户端网络地址解析和设置。
- 为
Server模块增加ssl_cafile/ssl_capath配置项。 - 增加
print_backtrace_on_error配置,此配置可以在发生位置错误时候,打印C函数的堆栈。 - 增加
Address Sanitizer调试工具。 - 增加
Cygwin测试,显著提升Cygwin平台下的兼容性和稳定性 - 在
macOS系统中,由于kqueue事件机制不支持跨进程管道事件监听,导致无法使用SWOOLE_PROCESS模式和Task进程功能。因此,系统将默认采用poll作为底层事件机制。如需启用kqueue,可以通过Swoole\Server::set(['enable_kqueue' => true])和swoole_async_set(['enable_kqueue' => true])方法手动开启。 - 升级
Swoole library版本。 - 禁用
-Wdate-time警告,解决使用 Zig/Clang 编译时的错误。 - 移除 PHP 8.0 相关兼容代码。
- 在
config.m4中新增SWOOLE_ODBC_LIBS变量。 - 确保
timespec.tv_nsec取值小于1,000,000,000,以符合 POSIX 标准规范。 - 重构
swoole协程化curl底层代码,提高与同步阻塞版本的兼容性。
⚠️ ** 注意事项**
- 自 Swoole 6.1 起,
Swoole\Coroutine\Http\Client与Swoole\Coroutine\Http\Server将自动处理 WebSocket 控制帧,除非显式设置open_websocket_ping_frame、open_websocket_pong_frame或open_websocket_close_frame。 Swoole\Coroutine::cancel()无法取消文件协程化操作,强行取消可能导致段错误。- 若启用
--enable-iouring,在检测到内核版本或liburing版本不满足要求时,将抛出警告信息。 Swoole\Websocket\Server::push方法在发送关闭帧后不会自动关闭连接,如需关闭连接,请使用Swoole\Websocket\Server::disconnect()方法。Swoole协议在处理控制帧时,会主动设置 FIN 标志位为 1,并确保不启用压缩(即 RSV1 位为 0),用户对此的设置将被忽略。- 当处理连续帧的压缩和发送时,
Swoole将压缩与数据分块的职责移交至应用层,用户需手动实现相关逻辑。具体请看最下面的例子。 - 系统默认启用了自动
HTTP 100 Continue响应功能。 - 在协程切换期间,将会保存并恢复
serialize与unsealize操作相关的全局变量。
💡 API 变更
新的锁 API
函数原型
namespace Swoole\Coroutine {
class Lock {
public function __construct(bool $shared = false) {}
public function lock(int $operation = LOCK_EX): bool {}
public function unlock(): bool {}
}
}
namespace Swoole {
class Lock {
public function __construct(int $type = SWOOLE_MUTEX) {}
public function lock(int $operation = LOCK_EX, float $timeout = -1): bool {}
public function unlock(): bool {}
}
}
namespace Swoole\Thread {
class Lock {
public function __construct(int $type = SWOOLE_MUTEX) {}
public function lock(int $operation = LOCK_EX, float $timeout = -1): bool {}
public function unlock(): bool {}
}
}使用示例
$lock = new Swoole\Lock;
$lock->lock(LOCK_EX | LOCK_NB, 0.5);
$lock->unlock();取消协程
Co\run(function () {
$cid = Co\go(function () {
try {
while (true) {
System::sleep(0.1);
echo "co 2 running\n";
}
var_dump('end');
} catch (Swoole\Coroutine\CanceledException $e) {
var_dump('cancelled');
}
});
System::sleep(0.3);
Co::cancel($cid, true);
System::sleep(0.2);
echo "co 1 end\n";
});WebSocket 压缩和发送连续帧
异步服务端
use Swoole\WebSocket\Server;
use Swoole\WebSocket\Frame;
$server = Server('127.0.0.1', 9502);
$server->set(['websocket_compression' => true]);
$server->on('message', function (Server $server, Frame $frame) {
$data1 = bin2hex(random_bytes(10 * 1024));
$data2 = bin2hex(random_bytes(20 * 2048));
$data3 = bin2hex(random_bytes(40 * 4096));
$context = deflate_init(ZLIB_ENCODING_RAW); // 流式压缩
$server->push($frame->fd, deflate_add($context, $data1, ZLIB_NO_FLUSH), SWOOLE_WEBSOCKET_OPCODE_TEXT, SWOOLE_WEBSOCKET_FLAG_COMPRESS | SWOOLE_WEBSOCKET_FLAG_RSV1);
$server->push($frame->fd, deflate_add($context, $data2, ZLIB_NO_FLUSH), SWOOLE_WEBSOCKET_OPCODE_CONTINUATION, 0);
$server->push($frame->fd, deflate_add($context, $data3, ZLIB_FINISH), SWOOLE_WEBSOCKET_OPCODE_CONTINUATION, SWOOLE_WEBSOCKET_FLAG_FIN);
});
$server->start();协程服务端
use function Swoole\Coroutine\run;
use Swoole\Coroutine\Http\Server;
run(function() {
$server = new Server("127.0.0.1", 9502);
$server->set(['websocket_compression' => true]);
$server->handle('/', function ($request, $response) use ($data1, $data2, $data3) {
$response->upgrade();
$data1 = bin2hex(random_bytes(10 * 1024));
$data2 = bin2hex(random_bytes(20 * 2048));
$data3 = bin2hex(random_bytes(40 * 4096));
$context = deflate_init(ZLIB_ENCODING_RAW);
$response->push(deflate_add($context, $data1, ZLIB_NO_FLUSH), SWOOLE_WEBSOCKET_OPCODE_TEXT, SWOOLE_WEBSOCKET_FLAG_COMPRESS | SWOOLE_WEBSOCKET_FLAG_RSV1);
$response->push(deflate_add($context, $data2, ZLIB_NO_FLUSH), SWOOLE_WEBSOCKET_OPCODE_CONTINUATION, 0);
$response->push(deflate_add($context, $data3, ZLIB_FINISH), SWOOLE_WEBSOCKET_OPCODE_CONTINUATION, SWOOLE_WEBSOCKET_FLAG_FIN);
});
});协程客户端
use function Swoole\Coroutine\run;
use Swoole\Coroutine\Http\Client;
run(function() {
$client = new Client('127.0.0.1', 9502);
$client->set(['websocket_compression' => true]);
$ret = $client->upgrade('/');
$context = deflate_init(ZLIB_ENCODING_RAW);
$client->push(deflate_add($context, $data1, ZLIB_NO_FLUSH), SWOOLE_WEBSOCKET_OPCODE_TEXT, SWOOLE_WEBSOCKET_FLAG_COMPRESS | SWOOLE_WEBSOCKET_FLAG_RSV1);
$client->push(deflate_add($context, $data2, ZLIB_NO_FLUSH), SWOOLE_WEBSOCKET_OPCODE_CONTINUATION, 0);
$client->push(deflate_add($context, $data3, ZLIB_FINISH), SWOOLE_WEBSOCKET_OPCODE_CONTINUATION, SWOOLE_WEBSOCKET_FLAG_FIN);
});🙏 致谢
诚挚感谢 @matyhtf @jingjingxyk @sy-records @KIMDONGYEON00 @ServBayDev @Appla @henderkes @NathanFreeman 所有贡献者的专业付出,Swoole 因你们而更强大!愿开源社区伙伴身体健康,万事如意,工作顺利。