Runtime Hooks allow Swoole 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 Swoole aims to support the existing ecosystem. Even native blocking PHP functions like
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, Swoole 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 Swoole Server request where the coroutine context is created for you for each request.
Coroutine hooks were first supported since Swoole 4.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
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 Swoole 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 Swoole 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 Swoole 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 Swoole v4.1.0, you can use any IO libraries based on
php_stream within a coroutine context.
Libraries with coroutine support:
phpredis) or (
mysqlnd) PDO and MySQLi
fopenand many more file I/O operations
Libraries without coroutine support:
You can enable coroutine support with hook Flags:
<?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 Swoole 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.
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
<?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_CURLfrom 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 Swoole 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 Swoole 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 Swoole 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.
Returns the currently set hook flags.
<?php // Enable all hooks Swoole\Runtime::setHookFlags(SWOOLE_HOOK_ALL); // Disable all hooks Swoole\Runtime::setHookFlags(0);