Join 4,000+ others and never miss out on new tips, tutorials, and more.
4.x is outdated, please check the latest version 22.x
Latest version:
pecl install openswoole-22.1.2
Runtime Hooks allow OpenSwoole to listen for internal PHP API calls, take control and execute your code in a non-blocking way, allowing us to use well known and tested libraries like the PDO extension or the CURL library. The benefit of using hooks is it allows us to use existing PHP ecosystem tools and libraries and not force us to use any coroutine specific clients, instead OpenSwoole aims to support the existing ecosystem. Even native blocking PHP functions like sleep
or file_get_contents
are supported, so it is easy to adopt coroutines throughout your application without much alteration to your existing codebase.
When hooks are enabled, OpenSwoole will take care of the coroutine scheduling for you under the hood, you don't need to write any additional logic with runtime hooks once they are setup and enabled. Hooks are required to run inside a coroutine context, this means you must use enabled hook functionality within a Co\run
or inside a OpenSwoole Server request where the coroutine context is created for you for each request.
Coroutine hooks were first supported since OpenSwoole v4.1.0
Before coroutine hooks, the alternative was to write a client for each use case, this included MySQL, Redis and even file operations etc. There would have to be a new client in order to support coroutines and make sure all IO operations are asynchronous. This task of managing multiple clients was a huge workload and it meant that a lot of duplicated API had to be done, so this became complex and even harder to scale when those clients needed updates or API changes. Coroutine clients were not native, they sat in front of native clients like PHP PDO
or phpredis
, meaning developers had to use an additional client.
The solution to all this complexity and confusion with additional coroutine specific clients is coroutine hooks. By enabling OpenSwoole runtime hooks, we can forget about using additional clients and use our existing PHP ecosystem libraries and extensions, while still having full support for coroutines and improved functionality support, adding hooks which work at the low level, meant that OpenSwoole could provider better support for coroutines in libraries like phpredis
and CURL. Developers only have to understand what hooks do and how to set them up, then they can continue developing as they would have done, rather than using an additional coroutine client.
Since the breakthrough with coroutine hooks, the old OpenSwoole coroutine clients are no longer recommended and it is suggested that you migrate to use coroutine hooks if you are still using the old coroutine client API objects.
Since OpenSwoole v4.1.0, you can use any IO libraries based on php_stream
within a coroutine context.
Libraries with coroutine support:
phpredis
) or (predis
)mysqlnd
) PDO and MySQLifile_get_contents
, fopen
and many more file I/O operationsstream_socket_client
functionsfsockopen
libcurl
Libraries without coroutine support:
libmysqlclient
mongo-c-client
pdo_pgsql
, pdo_ori
, pdo_odbc
, pdo_firebird
, php-amqp
You can enable coroutine support with hook Flags:
SWOOLE_HOOK_ALL
SWOOLE_HOOK_TCP
SWOOLE_HOOK_UNIX
SWOOLE_HOOK_UDP
SWOOLE_HOOK_UDG
SWOOLE_HOOK_SSL
SWOOLE_HOOK_TLS
SWOOLE_HOOK_SLEEP
SWOOLE_HOOK_FILE
SWOOLE_HOOK_STREAM_FUNCTION
SWOOLE_HOOK_BLOCKING_FUNCTION
SWOOLE_HOOK_PROC
SWOOLE_HOOK_CURL
SWOOLE_HOOK_NATIVE_CURL
SWOOLE_HOOK_SOCKETS
SWOOLE_HOOK_STDIO
<?php
Swoole\Runtime::enableCoroutine(bool $enable = true, int $flags = SWOOLE_HOOK_ALL);
// Or
Co::set(['hook_flags'=> SWOOLE_HOOK_ALL]);
The code above will enable coroutine support for all OpenSwoole Hooks, you can change which hooks you want to enable but it is likely better for performance to enable them all and take advantage of coroutines.
The enableCoroutine
call should be placed at the start of your script or at least before any Co\run
or server is used, this so that you can obtain 100% coverage. When calling enableCoroutine
it will take effect globally for the current process.
To enable multiple flags you must separate them using the pipe |
symbol:
<?php
Co::set(['hook_flags'=> SWOOLE_HOOK_TCP | SWOOLE_HOOK_SLEEP]);
Remember that enabling any hooks means you have to perform any operations inside a coroutine container for coroutine support
<?php
// Before v4.5.4
Swoole\Runtime::enableCoroutine(true, SWOOLE_HOOK_ALL | SWOOLE_HOOK_CURL);
SWOOLE_HOOK_ALL
containsSWOOLE_HOOK_CURL
from version v4.5.4
<?php
// All flags but not the sleep flag
Swoole\Runtime::enableCoroutine(true, SWOOLE_HOOK_ALL ^ SWOOLE_HOOK_SLEEP);
The coroutine scheduler is what OpenSwoole uses at a low level to manage different coroutine context containers and switch between other coroutines when one is waiting or blocking. Read more about the coroutine scheduler API to understand when it should be used. Most of the time you will never need to use it directly because OpenSwoole does it for you already.
<?php
$sch = new Swoole\Coroutine\Scheduler();
$sch->set(['hook_flags' => SWOOLE_HOOK_ALL]);
If you are inside a coroutine context or a OpenSwoole server, you can change hooks dynamically once they have been enabled:
<?php
// Enable all Swoole hooks at the beginning
Swoole\Runtime::enableCoroutine(true, SWOOLE_HOOK_ALL);
// Only use the TCP hook from now on...
Swoole\Runtime::enableCoroutine(true, SWOOLE_HOOK_TCP);
Hooks can be changed throughout the application, just take note that once any hooks are changed this will take affect globally for the current process, make sure other operations are not ongoing as this may affect them, removing or adding hooks. It is more recommended to enable hooks at the start of a PHP script so you get full coverage.
<?php
Swoole\Runtime::getHookFlags();
Returns the currently set hook flags.
<?php
// Enable all hooks
Swoole\Runtime::setHookFlags(SWOOLE_HOOK_ALL);
// Disable all hooks
Swoole\Runtime::setHookFlags(0);
<?php
Swoole\Runtime::enableCoroutine(false);