Swoole Runtime Hook Flags

What are coroutine hooks?

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 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, 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


Coroutine Hooks vs. Coroutine Clients

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 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.


Supported Libraries

Since Swoole v4.1.0, you can use any IO libraries based on php_stream within a coroutine context.

Libraries with coroutine support:

  • Redis (phpredis) or (predis)
  • MySQL (mysqlnd) PDO and MySQLi
  • PHP SOAP
  • file_get_contents, fopen and many more file I/O operations
  • stream_socket_client functions
  • fsockopen
  • CURL with libcurl

Libraries without coroutine support:

  • MySQL with libmysqlclient
  • MongoDB with mongo-c-client
  • pdo_pgsql, pdo_ori, pdo_odbc, pdo_firebird, php-amqp


Swoole Runtime Hook Flags

You can enable coroutine support with hook Flags:


Enabling and using Swoole Runtime Hooks

<?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.

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


Set Coroutine Runtime flags

<?php

// Before v4.5.4
Swoole\Runtime::enableCoroutine(true, SWOOLE_HOOK_ALL | SWOOLE_HOOK_CURL);

SWOOLE_HOOK_ALL contains SWOOLE_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);


Set Coroutine Scheduler Flags

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]);


Dynamic Coroutine Flags

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.


Get the Swoole Coroutine Runtime flags

<?php

Swoole\Runtime::getHookFlags();

Returns the currently set hook flags.


Set the Swoole Coroutine Runtime flags

<?php

// Enable all hooks
Swoole\Runtime::setHookFlags(SWOOLE_HOOK_ALL);

// Disable all hooks
Swoole\Runtime::setHookFlags(0);


Disable all coroutine hooks

<?php

Swoole\Runtime::enableCoroutine(false);