PHP
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions
-
Section 4: Object-Oriented PHP
-
Section 5: Working with Data
-
Section 6: Modern PHP (PHP 8)
-
Section 7: Working with Files and Networking
-
Section 8: Common PHP Frameworks Overview
-
Section 9: Tooling and Ecosystem
-
Section 10: Practical Projects
-
Section 11: Interview Practice
-
Section 12: More Standard Library
-
Section 13: Data Structures and Algorithms in PHP
-
Section 14: More Practice Exercises
-
Section 15: More Security and Best Practices
-
Section 16: More Testing and Tooling
-
Section 17: WordPress-Style CMS Concepts
-
Section 18: Advanced OOP Practice
-
Section 19: More Web Fundamentals
-
Section 20: Database Practice
-
Section 21: PHP Manual: Array Functions
-
Section 22: PHP Manual: Date and Calendar Functions
-
Section 23: PHP Manual: Filesystem and Directory Functions
-
Section 24: PHP Manual: Filter and Var Handling
-
Section 25: PHP Manual: Math Functions
-
Section 26: PHP Manual: JSON and XML
-
Section 27: PHP Manual: Network and Stream Functions
-
Section 28: PHP Manual: Error and Exception Handling
-
Section 29: PHP Manual: Output Control and Misc
-
Section 30: PHP Manual: FTP, Zip, and Mail
-
Section 31: Modern PHP Frameworks Deep Dive
-
Section 32: PHP Design Patterns
-
Section 33: More Practice Exercises
-
Section 34: PHP Performance and Deployment
-
Section 35: More Interview Practice
-
Section 36: More PHP Standard Library
-
Section 37: PHP Concurrency and Async
-
Section 38: More Web Development Practice
-
Section 39: PHP Testing Deep Dive
-
Section 40: Composer and Package Development
-
Section 41: PHP Security Deep Dive
-
Section 42: More Practical Projects
-
Section 43: Legacy PHP Maintenance
-
Section 44: More Algorithm Practice
-
Section 45: Final Practice and Review
-
Section 46: PHP for E-Commerce Patterns
-
Section 47: PHP API Design Deep Dive
-
Section 48: PHP Caching Strategies
-
Section 49: PHP Queue and Background Jobs
-
Section 50: PHP Multi-Tenancy Patterns
-
Section 51: PHP Real-Time Features
-
Section 52: PHP CMS and Content Modeling
-
Section 53: PHP Internationalization
-
Section 54: More Framework-Specific Practice
-
Section 55: PHP Legacy Code Refactoring
-
Section 56: More Practice Projects Round 2
-
Section 57: PHP Command-Line Applications
-
Section 58: PHP and Microservices
-
Section 59: More Interview and Review Round 2
158: Swoole for Async PHP
Up until now, we've lived in the world of PHP-FPM. You're used to the cycle: a request comes in, PHP boots up, executes your script, sends the response, and then promptly dies. It's a clean, shared-nothing architecture that saves us from a lot of memory leak headaches, but it's also incredibly wasteful when you're dealing with I/O-bound tasks.
The sequential bottleneck
Imagine you're building a dashboard that needs to aggregate data from three different external sources: a GitHub API for commits, a Stripe API for recent payments, and a custom internal CRM. In a traditional PHP setup, your code looks something like this:
$githubData = $httpClient->get('https://api.github.com/...');
$stripeData = $httpClient->get('https://api.stripe.com/...');
$crmData = $httpClient->get('https://crm.internal/...');
return json_encode(['github' => $githubData, 'stripe' => $stripeData, 'crm' => $crmData]);
On the surface, this is readable and straightforward. But here's the problem: it's blocking. If each of those APIs takes 300ms to respond, your user is staring at a loading spinner for nearly a full second. Your CPU isn't actually doing any work for 99% of that time; it's just sitting there, idling, waiting for a network packet to arrive. In a high-traffic environment, this is how you exhaust your PHP-FPM worker pool and start seeing 504 Gateway Timeouts, even though your server's CPU usage is barely at 5%.
Breaking the line with Swoole Coroutines
This is where Swoole changes the game. Instead of the "boot and die" model, Swoole runs PHP as a long-lived process with an event loop, similar to how Node.js or Go operate. The magic happens with coroutines. A coroutine allows PHP to "pause" the execution of a function when it hits an I/O operation and switch to another task, coming back only when the data is actually ready.
If we rewrite that aggregator using Swoole's coroutine scheduler, we can fire off all three requests concurrently. I usually wrap these in a waitGroup or use Swoole\Coroutine\go() to handle the concurrency:
use Swoole\Coroutine;
use Swoole\Coroutine\WaitGroup;
Coroutine\run(function () {
$wg = new WaitGroup();
$results = [];
$urls = [
'github' => 'https://api.github.com/...',
'stripe' => 'https://api.stripe.com/...',
'crm' => 'https://crm.internal/...',
];
foreach ($urls as $key => $url) {
$wg->add();
Coroutine\go(function () use ($wg, $url, $key, &$results) {
$client = new Swoole\Coroutine\Http\Client($url);
$client->get('/');
$results[$key] = $client->body;
$wg->done();
});
}
$wg->wait();
echo json_encode($results);
});
Now, instead of 300ms + 300ms + 300ms, your total wait time is roughly 300ms (the time of the slowest request). We've essentially collapsed the timeline. I've used this pattern to turn API endpoints that took 5 seconds to load into endpoints that take 400ms, without changing a single thing about the external APIs themselves.
The cost of staying alive
Now, I have to give you a warning. You can't just drop Swoole into a legacy Laravel or Symfony app and expect a magic speed boost. Because the PHP process doesn't die after the request, state persists. This is the "Gotcha" that trips up almost every developer moving to async PHP.
In PHP-FPM, if you accidentally add an item to a global array or a static property, it doesn't matter—it's wiped clean for the next request. In Swoole, that static array will grow and grow until you hit a memory limit and the worker crashes. You have to be incredibly disciplined about memory management and avoid using global or static variables to store request-specific data. You're no longer writing a script; you're writing a server application.
📋 Practical Task
Build a Concurrent Crypto Price Aggregator
Your task is to create a Swoole-powered script that fetches the current price of three different cryptocurrencies (e.g., Bitcoin, Ethereum, and Solana) from a public API (like CoinGecko or Binance).
- Implement the solution using
Swoole\Coroutine\go()to ensure the requests happen concurrently. - Use a
Swoole\Coroutine\WaitGroupto ensure the script only outputs the final JSON result once all three API calls have completed. - Measure the execution time using
microtime(true)at the start and end of theCoroutine\runblock to prove that the total time is closer to a single request's duration than the sum of all three.
There are no comments for now.