Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Modern PHP 8.3+ development with strict typing, PHPStan level 9, PSR standards, and Laravel/Symfony support.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/async-patterns.md
1# Async PHP Patterns23## Swoole HTTP Server45```php6<?php78declare(strict_types=1);910use Swoole\HTTP\Server;11use Swoole\HTTP\Request;12use Swoole\HTTP\Response;1314$server = new Server('0.0.0.0', 9501);1516$server->set([17'worker_num' => 4,18'max_request' => 10000,19'task_worker_num' => 2,20'enable_coroutine' => true,21]);2223$server->on('start', function (Server $server) {24echo "Swoole HTTP server started at http://0.0.0.0:9501\n";25});2627$server->on('request', function (Request $request, Response $response) {28$response->header('Content-Type', 'application/json');2930match ($request->server['request_uri']) {31'/api/users' => handleUsers($request, $response),32'/api/health' => $response->end(json_encode(['status' => 'healthy'])),33default => $response->status(404)->end(json_encode(['error' => 'Not found'])),34};35});3637function handleUsers(Request $request, Response $response): void38{39// Coroutine for concurrent DB queries40go(function () use ($response) {41$users = queryDatabase('SELECT * FROM users LIMIT 10');42$response->end(json_encode(['data' => $users]));43});44}4546$server->start();47```4849## Swoole Coroutines5051```php52<?php5354declare(strict_types=1);5556use Swoole\Coroutine;57use Swoole\Coroutine\Http\Client;5859// Concurrent HTTP requests60Coroutine\run(function () {61$results = [];6263// Create multiple coroutines64$wg = new Coroutine\WaitGroup();6566$urls = [67'https://api.example.com/users',68'https://api.example.com/posts',69'https://api.example.com/comments',70];7172foreach ($urls as $url) {73$wg->add();74go(function () use ($url, &$results, $wg) {75$client = new Client(parse_url($url, PHP_URL_HOST), 443, true);76$client->set(['timeout' => 5]);77$client->get(parse_url($url, PHP_URL_PATH));7879$results[$url] = [80'status' => $client->statusCode,81'body' => $client->body,82];8384$client->close();85$wg->done();86});87}8889$wg->wait();9091print_r($results);92});93```9495## Swoole Async MySQL9697```php98<?php99100declare(strict_types=1);101102use Swoole\Coroutine;103use Swoole\Coroutine\MySQL;104105Coroutine\run(function () {106$mysql = new MySQL();107108$connected = $mysql->connect([109'host' => '127.0.0.1',110'port' => 3306,111'user' => 'root',112'password' => 'password',113'database' => 'test',114]);115116if (!$connected) {117throw new \RuntimeException($mysql->connect_error);118}119120// Async query121$result = $mysql->query('SELECT * FROM users WHERE active = 1');122123foreach ($result as $row) {124echo "User: {$row['name']}\n";125}126127// Prepared statements128$stmt = $mysql->prepare('SELECT * FROM users WHERE id = ?');129$stmt->execute([42]);130$user = $stmt->fetchAll();131132$mysql->close();133});134```135136## Swoole Channel (Communication)137138```php139<?php140141declare(strict_types=1);142143use Swoole\Coroutine;144use Swoole\Coroutine\Channel;145146Coroutine\run(function () {147$channel = new Channel(10); // Buffer size: 10148149// Producer150go(function () use ($channel) {151for ($i = 1; $i <= 5; $i++) {152$channel->push("Task {$i}");153echo "Produced: Task {$i}\n";154Coroutine::sleep(0.5);155}156$channel->close();157});158159// Consumer160go(function () use ($channel) {161while (true) {162$task = $channel->pop();163if ($task === false && $channel->errCode === SWOOLE_CHANNEL_CLOSED) {164break;165}166echo "Consumed: {$task}\n";167Coroutine::sleep(1);168}169});170});171```172173## ReactPHP Event Loop174175```php176<?php177178declare(strict_types=1);179180require 'vendor/autoload.php';181182use React\EventLoop\Loop;183use React\Http\Message\Response;184use Psr\Http\Message\ServerRequestInterface;185186// HTTP Server187$server = new React\Http\HttpServer(function (ServerRequestInterface $request) {188return new Response(189200,190['Content-Type' => 'application/json'],191json_encode([192'method' => $request->getMethod(),193'uri' => (string) $request->getUri(),194'timestamp' => time(),195])196);197});198199$socket = new React\Socket\SocketServer('0.0.0.0:8080');200$server->listen($socket);201202echo "Server running at http://0.0.0.0:8080\n";203204// Periodic timer205Loop::addPeriodicTimer(5.0, function () {206echo "Heartbeat: " . date('H:i:s') . "\n";207});208209// One-time timer210Loop::addTimer(10.0, function () {211echo "This runs once after 10 seconds\n";212});213```214215## ReactPHP Async MySQL216217```php218<?php219220declare(strict_types=1);221222require 'vendor/autoload.php';223224use React\MySQL\Factory;225use React\MySQL\QueryResult;226227$factory = new Factory();228229$connection = $factory->createLazyConnection('root:password@localhost/database');230231$connection->query('SELECT * FROM users WHERE active = 1')232->then(233function (QueryResult $result) {234echo "Found " . count($result->resultRows) . " users\n";235foreach ($result->resultRows as $row) {236echo "User: {$row['name']}\n";237}238},239function (\Exception $error) {240echo "Error: " . $error->getMessage() . "\n";241}242);243244// Prepared statements245$connection->query('SELECT * FROM users WHERE id = ?', [42])246->then(function (QueryResult $result) {247$user = $result->resultRows[0] ?? null;248var_dump($user);249});250```251252## ReactPHP Promises253254```php255<?php256257declare(strict_types=1);258259use React\Promise\Promise;260use React\Promise\Deferred;261use function React\Promise\all;262263// Creating promises264function fetchUser(int $id): Promise265{266$deferred = new Deferred();267268// Simulate async operation269Loop::addTimer(1.0, function () use ($deferred, $id) {270$deferred->resolve([271'id' => $id,272'name' => "User {$id}",273]);274});275276return $deferred->promise();277}278279// Using promises280fetchUser(42)281->then(function ($user) {282echo "Got user: {$user['name']}\n";283return fetchUserPosts($user['id']);284})285->then(function ($posts) {286echo "Got " . count($posts) . " posts\n";287})288->catch(function (\Exception $error) {289echo "Error: " . $error->getMessage() . "\n";290});291292// Parallel promises293all([294fetchUser(1),295fetchUser(2),296fetchUser(3),297])->then(function ($users) {298echo "Fetched " . count($users) . " users\n";299});300```301302## PHP Fibers (Native PHP 8.1+)303304```php305<?php306307declare(strict_types=1);308309// Simple async function using fibers310function async(callable $callback): Fiber311{312return new Fiber($callback);313}314315function await(Fiber $fiber): mixed316{317if (!$fiber->isStarted()) {318return $fiber->start();319}320if ($fiber->isTerminated()) {321return $fiber->getReturn();322}323return $fiber->resume();324}325326// Simulate async I/O327function fetchData(string $url): Fiber328{329return async(function () use ($url) {330echo "Fetching: {$url}\n";331Fiber::suspend('pending');332333// Simulate network delay334sleep(1);335336return "Data from {$url}";337});338}339340// Usage341$fiber1 = fetchData('https://api.example.com/users');342$fiber2 = fetchData('https://api.example.com/posts');343344await($fiber1);345await($fiber2);346347$result1 = await($fiber1);348$result2 = await($fiber2);349350echo "{$result1}\n";351echo "{$result2}\n";352```353354## Amphp Framework355356```php357<?php358359declare(strict_types=1);360361require 'vendor/autoload.php';362363use Amp\Http\Server\HttpServer;364use Amp\Http\Server\Request;365use Amp\Http\Server\Response;366use Amp\Http\Server\Router;367use Amp\Socket\Server as SocketServer;368use function Amp\async;369use function Amp\Future\await;370371// HTTP Server with Amphp372$router = new Router();373374$router->addRoute('GET', '/api/users', function (Request $request): Response {375// Concurrent database queries376$users = await([377async(fn() => queryUsers()),378async(fn() => queryUserStats()),379]);380381return new Response(382status: 200,383headers: ['content-type' => 'application/json'],384body: json_encode(['users' => $users[0], 'stats' => $users[1]]),385);386});387388$server = new HttpServer(389servers: [SocketServer::listen('0.0.0.0:8080')],390requestHandler: $router,391);392393$server->start();394```395396## Quick Reference397398| Technology | Use Case | Performance |399|------------|----------|-------------|400| Swoole | High-performance servers, WebSockets | Very High |401| ReactPHP | Event-driven apps, real-time | High |402| Amphp | Modern async framework | High |403| Fibers | Native async (PHP 8.1+) | Medium |404| Generators | Simple async patterns | Medium |405406| Feature | Swoole | ReactPHP | Amphp |407|---------|--------|----------|-------|408| Coroutines | Yes | No (Promises) | Yes (Fibers) |409| HTTP Server | Built-in | Via package | Via package |410| WebSockets | Built-in | Via package | Via package |411| Extension | Required | Not required | Not required |412| Learning Curve | Medium | Low | Medium |413