async
A cooperative event loop for HolyPHP: timers, socket watchers, line-oriented TCP servers, and HTTP — all in one loop, no threads needed. Pure HolyPHP on top of the runtime's non-blocking socket primitives.
stdlib — embedded
timers
socket watchers
HTTP client + server
single event loop
Timers
import "async";
$loop = new Loop();
$loop->after(1000, function() { echo "one second passed"; });
$loop->every(250, function() { echo "tick"; });
$loop->run(); // blocks until stop() or nothing left to wait on
| Method | Returns | What it does |
|---|---|---|
after(int $ms, $fn) | int | one-shot timer; returns an id for cancelTimer |
every(int $ms, $fn) | int | repeating timer (self-reschedules) |
cancelTimer(int $id) | void | cancel a pending timer |
stop() | void | leave run() from inside a callback |
tick(int $maxWaitMs = 25) | bool | run one poll iteration yourself |
run() | void | loop until stop() or idle |
TCP: servers, watchers, lines
import "async";
// one-shot TCP server: accept callback per connection
$loop = new Loop();
$loop->listen("tcp://127.0.0.1:8080", function($client, $peer) {
stream_send($client, "hello $peer\n");
stream_close($client);
});
// raw readable-socket watcher
$loop->watch($sock, function($sock, $chunk, $eof) {
if ($eof) { return; }
echo "got: $chunk";
});
// line-oriented server with automatic ACK replies
$lp = async_line_server("tcp://0.0.0.0:9000", function($client, $line) {
return "ACK:" . strtoupper($line); // non-null return = reply line
});
$lp->run();
Loop async_line_server(string $addr, $onLine, $onConnect = null)
LineReader assembles stream chunks into complete \n
lines — handy for simple TCP protocols (works with raw threads too).
HTTP
import "async";
$loop = new Loop();
// in-loop GET: the loop stays live (timers + other sockets keep firing)
$loop->httpGet("http://service.local/api", function($resp) {
echo "status: " . substr($resp, 0, 15);
}, function($err) {
echo "failed: $err";
});
// blocking shape: runs a private loop, returns when done
async_get("http://example.invalid/", function($resp) {
file_put_contents("out.html", $resp);
});
$loop->run();
bool Loop::httpGet(string $url, $onDone, $onError = null) // composable primitive, 10 s timeout
bool async_get(string $url, $onDone, $onError = null) // blocking convenience wrapper
Responses arrive as the full HTTP payload (status line +
headers + body). For parallel fetches call async_get from several
thread workers.
Sockets + threads
Sockets are process-global, so one thread's loop serves connections while the
main thread blocks in async_get — the two libraries compose:
import "async";
import "thread";
$ready = chan_new(1);
thr_spawn(function() use ($ready) {
$lp = new Loop();
$lp->listen("tcp://127.0.0.1:8934", function($c, $peer) {
stream_send($c, "HTTP/1.1 200 OK\r\nContent-Length: 5\r\nConnection: close\r\n\r\nHELLO");
stream_close($c);
});
chan_send($ready, "listening");
$lp->run();
});
chan_recv($ready);
async_get("http://127.0.0.1:8934/x", function($resp) {
echo $resp; // HTTP/1.1 200 OK ...
});
Try it
hphp pkg install async
hphp run examples/async_demo.hphp
Ships embedded in the compiler — import "async"
works offline, no install needed. Source: lib/async/async.hphp.