fiber-interop

Integrations

Packages that make an existing blocking library cooperative on top of fiber-interop/api. Each one works on every adapter: through a native driver where the runtime has one, otherwise through a generic driver written against the api alone. Outside async\run() each behaves exactly like the library it wraps.

curl: fiber-interop/curl

async\curl\exec(\CurlHandle $h) has curl_exec()'s contract (return value, curl_errno(), CURLOPT_RETURNTRANSFER), but suspends only the calling task. async\curl\start($h) begins the transfer now and returns an awaitable. README

composer require fiber-interop/curl
Runtime Driver
phasync with the phasync extension native: the extension makes curl_exec() cooperative
phasync without the extension generic MultiDriver
Swoole built with --enable-swoole-curl native: SWOOLE_HOOK_NATIVE_CURL
Swoole without native curl generic MultiDriver
Revolt, AMPHP, ReactPHP generic MultiDriver

The generic driver polls one shared curl_multi handle with async\sleep() (1 ms after activity, backing off to 10 ms). PHP exposes no file descriptor or socket callback for curl_multi, so there is nothing to hand to an event loop; a php-src change exposing CURLMOPT_SOCKETFUNCTION / CURLMOPT_TIMERFUNCTION (or a selectable fd) would remove the polling.

Guzzle: fiber-interop/guzzle

A Guzzle handler built on async\curl\start(), structured like Guzzle's own CurlHandler, so responses and exceptions are Guzzle's. Concurrent get() calls in separate tasks overlap, and so do getAsync() promises inside one task. README

composer require fiber-interop/guzzle
$client = async\guzzle\client(['base_uri' => 'https://example.com']);

One line of configuration is needed: Guzzle chooses its default handler in the static Utils::chooseHandler(), which has no override. A Utils::setDefaultHandler() in Guzzle would let installing the package be enough. Drivers per runtime are those of fiber-interop/curl.

pg: fiber-interop/pg

async\pg\query() and async\pg\query_params() have the contracts of pg_query() and pg_query_params() (the result, or false with pg_last_error() set), but suspend only the calling task. async\pg\start() sends the query now and returns an awaitable. async\pg\connect() is pg_connect() using PGSQL_CONNECT_ASYNC and pg_connect_poll(). Version 0.1.0; 9/9 tests pass on Revolt, AMPHP, ReactPHP, phasync and Swoole. README

composer require fiber-interop/pg
Runtime Driver
Revolt, AMPHP, ReactPHP, phasync (with or without the extension), Swoole generic SocketDriver

There are no native drivers. The generic driver waits on the real socket from pg_socket() with async\readable(), so there is no polling: libpq hands out its descriptor and the event loop watches it directly. Use one connection per task for parallelism; libpq runs one query at a time per connection.

Coming

mysqli.