PHP TRUE ASYNC is an experimental PHP extension that provides a true asynchronous, tightly integrated at the core level.
Coming soon!
PHP TRUE ASYNC is supported for PHP 8.5.0 and later. LibUV is the primary reactor implementation for this extension.
# Build the image docker build -t true-async-php . # Run interactively docker run -it true-async-php bash # Check TrueAsync module docker run --rm true-async-php php -m | grep true_async- PHP 8.5.0+
- LibUV β₯ 1.45.0 (required) - Fixes critical
UV_RUN_ONCEbusy loop issue that could cause high CPU usage
Prior to libuv 1.44, there was a critical issue in uv__io_poll()/uv__run_pending logic that could cause the event loop to "stick" after the first callback when running in UV_RUN_ONCE mode, especially when new ready events appeared within callbacks. This resulted in:
- High CPU usage due to busy loops
- Performance degradation in async applications
- Inconsistent event loop behavior affecting TrueAsync API reliability
The fix in libuv 1.44 ensures that UV_RUN_ONCE properly returns after processing all ready callbacks in the current iteration, meeting the "forward progress" specification requirements. This is essential for TrueAsync's performance and reliability.
-
Clone the PHP repository:
for example, basic directory name is
php-src:git clone https://github.com/true-async/php-src -b true-async-api ./php-src -
Clone the
True Asyncextension repository:to the
extdirectory of your PHP source:git clone https://github.com/true-async/php-async ./php-src/ext/async -
Install PHP development tools:
Make sure you have the necessary development tools installed. On Debian/Ubuntu, you can run:
sudo apt-get install php-dev build-essential autoconf libtool pkg-configFor macOS, you can use Homebrew:
brew install autoconf automake libtool pkg-config -
Install LibUV::
IMPORTANT: LibUV version 1.45.0 or later is required.
For Debian/Ubuntu:
# Check if system libuv meets requirements (β₯1.45.0) pkg-config --modversion libuv # If version is too old, install from source: wget https://github.com/libuv/libuv/archive/v1.45.0.tar.gz tar -xzf v1.45.0.tar.gz cd libuv-1.45.0 mkdir build && cd build cmake .. -DCMAKE_BUILD_TYPE=Release make -j$(nproc) sudo make install sudo ldconfigFor macOS:
# Homebrew usually has recent versions brew install libuvPlease see the LibUV installation guide for more details.
-
Configure and build:
./buildconf ./configure --enable-async make && sudo make installWe can use
--enable-debugto enable debug mode, which is useful for development.Note: The
--enable-experimental-async-apioption is no longer needed as the Async API is now enabled by default in the core.
-
Install php-sdk:
Download and set up php-sdk for building PHP extensions on Windows. -
Install and build LibUV:
You can use vcpkg or build libuv from source. -
Copy LibUV files to PHP SDK directories:
1. Copy everything from 'libuv\include' to '%PHP_SDK_PATH%\deps\include\libuv\' 2. Copy 'libuv.lib' to '%PHP_SDK_PATH%\deps\lib\'%PHP_SDK_PATH%is your php-sdk installation root. -
Configure and build the extension with PHP:
cd \path\to\php-src buildconf configure --enable-async nmakeNote: The
--enable-experimental-async-apioption is no longer needed as the Async API is now enabled by default in the core.
50+ PHP functions have been adapted to work asynchronously when used within coroutines:
gethostbyname()- resolve hostname to IP addressgethostbyaddr()- resolve IP address to hostnamegethostbynamel()- get list of IP addresses for hostname
- PDO MySQL - async-compatible PDO operations
PDO::__construct(),PDO::prepare(),PDO::exec()- non-blockingPDOStatement::execute(),PDOStatement::fetch()- async data access
- MySQLi - async-compatible MySQLi operations
mysqli_connect(),mysqli_query(),mysqli_prepare()- non-blockingmysqli_stmt_execute(),mysqli_fetch_*()- async result fetching
curl_exec()- execute cURL requestcurl_multi_exec()- execute multiple cURL handlescurl_multi_select()- wait for activity on multiple cURL handlescurl_multi_getcontent()- get content from multi handlecurl_setopt(),curl_getinfo(),curl_error(),curl_close()- async-aware
socket_connect(),socket_accept()- connection operationssocket_read(),socket_write()- data transfersocket_send(),socket_recv()- data exchangesocket_sendto(),socket_recvfrom()- addressed data transfersocket_bind(),socket_listen()- server operationssocket_select()- monitor socket activity
file_get_contents()- get file/URL contentsfread(),fwrite()- file I/O operationsfopen(),fclose()- file handle managementstream_socket_client(),stream_socket_server()- socket streamsstream_socket_accept()- accept stream connectionsstream_select()- monitor stream activitystream_context_create()- async-aware context creation
proc_open()- open process with pipesexec()- execute external commandshell_exec()- execute shell commandsystem()- execute system commandpassthru()- execute and pass output directly
sleep()- delay execution (seconds)usleep()- delay execution (microseconds)time_nanosleep()- nanosecond precision delaytime_sleep_until()- sleep until timestamp
ob_start()- start output buffering with coroutine isolationob_flush(),ob_clean()- buffer operations with isolationob_get_contents(),ob_end_clean()- get/end buffer with isolation
All functions automatically become non-blocking when used in async context, allowing other coroutines to continue execution while waiting for I/O operations to complete.
<?php // Spawn multiple concurrent coroutines Async\spawn(function() { echo "Starting coroutine 1\n"; sleep(2); // Non-blocking in async context echo "Coroutine 1 completed\n"; }); Async\spawn(function() { echo "Starting coroutine 2\n"; sleep(1); // Non-blocking in async context echo "Coroutine 2 completed\n"; }); echo "All coroutines started\n";<?php $start = microtime(true); // Start multiple DNS lookups concurrently Async\spawn(function() { $ip = gethostbyname('github.com'); // Non-blocking $ips = gethostbynamel('github.com'); // Get all IPs echo "GitHub: $ip (" . count($ips) . " total IPs)\n"; }); Async\spawn(function() { $ip = gethostbyname('google.com'); // Non-blocking $hostname = gethostbyaddr($ip); // Reverse lookup echo "Google: $ip -> $hostname\n"; }); Async\spawn(function() { $content = file_get_contents('http://httpbin.org/ip'); // Non-blocking echo "External IP: " . json_decode($content)->origin . "\n"; }); $elapsed = microtime(true) - $start; echo "All operations completed in: " . round($elapsed, 3) . "s\n";<?php $urls = [ 'https://httpbin.org/delay/1', 'https://httpbin.org/delay/2', 'https://httpbin.org/delay/1' ]; $start = microtime(true); foreach ($urls as $i => $url) { Async\spawn(function() use ($url, $i) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 10); $response = curl_exec($ch); // Non-blocking $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); echo "Request $i: HTTP $httpCode\n"; }); } $elapsed = microtime(true) - $start; echo "All requests completed in: " . round($elapsed, 3) . "s\n";<?php // Concurrent database queries with PDO MySQL Async\spawn(function() { $pdo = new PDO('mysql:host=localhost;dbname=test', $user, $pass); // All operations are non-blocking in async context $stmt = $pdo->prepare("SELECT * FROM users WHERE active = ?"); $stmt->execute([1]); while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { echo "User: {$row['name']}\n"; } }); // MySQLi concurrent operations Async\spawn(function() { $mysqli = new mysqli('localhost', $user, $pass, 'test'); // Non-blocking query execution $result = $mysqli->query("SELECT COUNT(*) as total FROM orders"); $row = $result->fetch_assoc(); echo "Total orders: {$row['total']}\n"; $mysqli->close(); }); echo "Database queries started\n";<?php // Execute multiple commands concurrently Async\spawn(function() { $output = shell_exec('sleep 2 && echo "Command 1 done"'); // Non-blocking echo $output; }); Async\spawn(function() { $output = shell_exec('sleep 1 && echo "Command 2 done"'); // Non-blocking echo $output; }); echo "Commands started\n";<?php // Each coroutine has isolated output buffer Async\spawn(function() { ob_start(); // Isolated buffer echo "Output from coroutine 1\n"; echo "More output from coroutine 1\n"; $buffer1 = ob_get_contents(); ob_end_clean(); echo "Coroutine 1 captured: $buffer1"; }); Async\spawn(function() { ob_start(); // Separate isolated buffer echo "Output from coroutine 2\n"; $buffer2 = ob_get_contents(); ob_end_clean(); echo "Coroutine 2 captured: $buffer2"; }); echo "Buffers are isolated between coroutines\n";Pull requests and suggestions are welcome!
Please read CONTRIBUTING.md before starting.
- π οΈ php-src/true-async-api
- π php-async
- π php-true-async-rfc
PHP TRUE ASYNC β modern async PHP, today!