Swoole
repository·master·Indexed 12 days ago
https://github.com/swoole/swoole-srcAn event-driven, asynchronous, coroutine-based concurrency library for PHP designed for high performance. It enables the creation of high-performance HTTP, WebSocket, and TCP servers, and provides coroutine clients for MySQL, Redis, and HTTP. Swoole features runtime hooks that convert standard blocking PHP functions into non-blocking I/O, supporting extensions like ext-curl, ext-redis, and PDO.
What's inside Swoole
- Hiredis is a minimalistic C client library for the Redis database. It provides a high-level, printf-like API for sending commands and receiving replies. It supports the binary-safe Redis protocol (compatible with Redis version >= 1.2.0).
Use the standalone pdo_oci PECL package
masterStarting from PHP 8.4, the
pdo_ociextension has been removed from the PHP core and migrated to a standalone PECL package. If you require the version maintained by the PHP core (which includes specific modifications made in May 2025), note that the current PECL version (1.1.0) may differ from the core implementation.- PECL Package: https://pecl.php.net/package/pdo_oci
- GitHub Repository: https://github.com/php/pecl-database-pdo_oci
Use the Hiredis Asynchronous API
masterHiredis provides an asynchronous API designed to work with event libraries (like
libevorlibevent). It uses a non-blocking connection model where commands are automatically pipelined.Key Concepts:
- Non-blocking Connection:
redisAsyncConnectreturns aredisAsyncContextimmediately. You must check theerrfield to verify if the connection attempt was successful. - Thread Safety: A
redisAsyncContextis not thread-safe. - Lifecycle: The context object is automatically freed after the disconnect callback is executed.
- Event Loop Integration: To use Hiredis with an event library, you must set specific hooks on the context object after creation (refer to
adapters/forlibevandlibeventimplementations).
redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); if (c->err) { printf("Error: %s\n", c->errstr); // handle error }- Non-blocking Connection:
How the IOCP Readiness Bridge works for cURL
masterTo bridge the completion-based IOCP API with
libcurl's readiness-basedcurl_multi_socket_action()API, Swoole performs the following:- Socket Monitoring:
libcurlinvokesCURLMOPT_SOCKETFUNCTIONto request monitoring for specific events (CURL_POLL_IN,CURL_POLL_OUT, etc.). - Probe Submission: Swoole submits zero-length overlapped operations to the socket:
- Read Interest:
WSARecvwith a zero-lengthWSABUF. - Write Interest:
WSASendwith a zero-lengthWSABUF.
- Read Interest:
- Completion Handling: When the IOCP dispatcher receives a completion packet, it records the corresponding event bit (
CURL_CSELECT_IN,CURL_CSELECT_OUT, orCURL_CSELECT_ERR) and resumes the coroutine. - Actual I/O: The resumed coroutine calls
selector_finish(), which triggerscurl_multi_socket_action().libcurlthen performs the real data transfer.
Note on Data Integrity: Because the probes use zero-byte buffers, no payload data is intercepted or corrupted by Swoole;
libcurlremains the sole authority for reading and writing application bytes.// Example of zero-byte probe buffers used by Swoole WSABUF buffer; buffer.buf = &dummy; buffer.len = 0; // For read interest WSARecv(sockfd, &buffer, 1, &bytes, &flags, &overlapped, nullptr); // For write interest WSASend(sockfd, &buffer, 1, &bytes, 0, &overlapped, nullptr);- Socket Monitoring:
Understand Swoole support lifecycles
masterSwoole defines two types of support for its releases:
- Active support: The release is actively maintained. This includes regular point releases and fixes for reported bugs and security issues.
- Security fixes only: The release is only maintained for critical security issues. Updates are made on an as-needed basis rather than through regular release cycles.
Transform synchronous PHP libraries into coroutines
masterSince Swoole v4.1.0, you can transform synchronous PHP network libraries (like
php-redis,PDO,mysqli, or standard stream functions) into asynchronous coroutine-friendly libraries using a single method call.By calling
Swoole\Runtime::enableCoroutine()at the very top of your script, the Swoole kernel replaces ZendVM stream function pointers. This allows socket operations inphp_streambased extensions to be dynamically converted to asynchronous IO scheduled by the coroutine runtime.Supported operations include:
- Network IO (TCP/UDP/Unix sockets)
- File IO (read, write, delete)
- Database communication (PDO, MySQLi)
- Standard PHP functions like
usleep,file_get_contents, andstream_socket_client.
Swoole\Runtime::enableCoroutine(); Co\run(function() { // Now, even synchronous-looking code runs asynchronously within coroutines $redis = new Redis(); $redis->connect('127.0.0.1', 6379); echo $redis->get('awesome'); });How Runtime Hooks Work
masterSwoole hooks blocking I/O functions at the bottom layer and automatically converts them to non-blocking functions. This allows standard PHP blocking functions to be called concurrently within coroutines without stalling the entire process.
To enable this, use
$server->set(['hook_flags' => SWOOLE_HOOK_ALL]);or similar configuration.Use Channels for Coroutine Communication
masterA
Swoole\Coroutine\Channelis the primary mechanism for exchanging data between coroutines, following the CSP (Communicating Sequential Processes) programming model.Common use cases include:
- Connection Pools: Managing a fixed set of resources (like Redis connections) to prevent overloading the server.
- Producer/Consumer Patterns: Coordinating multiple coroutines to perform tasks and collect results efficiently.
Customize Redis reply objects
masterWhen using the
redisReaderAPI, you can customize howredisReplyobjects are instantiated. This is useful for creating language-specific objects (e.g., Ruby or Python objects) directly from the parser.To do this, set the
fnfield on theredisReaderstruct immediately after callingredisReaderCreate().Use the Hiredis Synchronous API
masterThe synchronous API allows for straightforward command execution. The core workflow involves:
- Creating a
redisContextviaredisConnect. - Issuing commands using
redisCommandorredisCommandArgv. - Processing the
redisReplyobject. - Cleaning up the reply with
freeReplyObjectand the context withredisFree.
Note: A
redisContextis not thread-safe.redisContext *redisConnect(const char *ip, int port); void *redisCommand(redisContext *c, const char *format, ...); void freeReplyObject(void *reply);- Creating a
Understand the Windows IOCP cURL Runtime Design
masterSwoole's native cURL coroutine runtime on Windows uses an IOCP Readiness Bridge rather than a full data-path transport.
Key Concepts:
- Ownership:
libcurlretains full ownership of the transfer state machine, including TLS state, HTTP/1.1/2 protocols, proxy negotiation, and actual socket I/O (reads/writes). - Mechanism: Swoole uses Windows overlapped I/O and IOCP to act as a readiness adapter. It submits zero-byte
WSARecvandWSASendoperations to trigger IOCP completion packets. - Flow: When an IOCP completion is received, Swoole does not consume payload data. Instead, it uses the completion as a signal to resume the bound coroutine, which then calls
curl_multi_socket_action()to letlibcurlperform the actual I/O. - Purpose: This design allows Swoole to use its existing IOCP reactor for coroutine scheduling on Windows without re-implementing the complex HTTP/TLS stack.
- Ownership:
Understand Swoole Coroutines
masterSwoole 4.x+ provides built-in coroutines that allow you to write fully synchronized, synchronous-looking PHP code that achieves asynchronous performance. The underlying coroutine scheduler handles the switching automatically without requiring additional keywords in your PHP code.
Coroutines are ultra-lightweight threads, enabling you to spawn thousands of them within a single process to handle high concurrency.