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.
- PHP 8.5.0+
- LibUV β₯ 1.44.0 (required) - Fixes critical
UV_RUN_ONCE
busy 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 Async
extension repository:to the
ext
directory 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-config
For macOS, you can use Homebrew:
brew install autoconf automake libtool pkg-config
-
Install LibUV::
IMPORTANT: LibUV version 1.44.0 or later is required.
For Debian/Ubuntu:
# Check if system libuv meets requirements (β₯1.44.0)
pkg-config --modversion libuv
# If version is too old, install from source:
wget https://github.com/libuv/libuv/archive/v1.44.0.tar.gz
tar -xzf v1.44.0.tar.gz
cd libuv-1.44.0
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j$(nproc)
sudo make install
sudo ldconfig
For macOS:
# Homebrew usually has recent versions
brew install libuv
Please see the LibUV installation guide for more details.
-
Configure and build:
./buildconf ./configure --enable-async make && sudo make install
We can use
--enable-debug
to enable debug mode, which is useful for development.Note: The
--enable-experimental-async-api
option 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 nmake
Note: The
--enable-experimental-async-api
option 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
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
// 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!