What you'll learn
Optimize the bottleneck the system actually has. Understand PHP's request execution model, OPcache, memory behavior, I/O waits, profiling, and load testing so performance changes are driven by traces and budgets instead of folklore.
By the end of this lesson, you'll be able to:
- Explain PHP-FPM and OPcache behavior
- Profile CPU, memory, queries, and external I/O
- Design a representative load test and performance budget
Core mental model
Professional PHP is less about memorizing APIs and more about choosing a clear boundary for each responsibility. Use this table as a decision guide while reading the examples.
| Concept | What it protects | Decision rule |
|---|---|---|
| OPcache | Compiled opcode reuse | Enable and size it for production code volume. |
| Profiler | Runtime evidence | Measure call time, allocations, SQL, and external waits before changing code. |
| Percentile | Tail-latency visibility | Track p50, p95, and p99—not only averages. |
Professional workflow
Build the feature in small, verifiable steps. Each step leaves the system in a state you can test.
- Describe the performance investigation boundary: its inputs, outputs, invariants, and expected failures.
- Implement the smallest happy path behind an explicit contract.
- Add validation and translate low-level failures into language the caller understands.
- Exercise the boundary with realistic data, then inspect output, logs, and resource cleanup.
- Refactor only after behavior is protected by a repeatable check.
Make the boundary visible
Guided code lab
Stream instead of buffering
The generator and streamed response keep memory bounded as export size grows.
<?php
function exportRows(PDO $db): Generator
{
$statement = $db->query('SELECT id, email FROM users ORDER BY id');
while ($row = $statement->fetch(PDO::FETCH_ASSOC)) yield $row;
}
foreach (exportRows($db) as $row) {
echo implode(',', array_map('strval', $row)) . "\n";
if (ob_get_level() > 0) ob_flush();
flush();
}Record a small timing span
Monotonic high-resolution time avoids wall-clock adjustments and logs useful dimensions.
<?php
$started = hrtime(true);
try {
return $catalog->featured();
} finally {
$logger->info('catalog.featured.completed', [
'duration_ms' => (hrtime(true) - $started) / 1_000_000,
'memory_peak_bytes' => memory_get_peak_usage(true),
'request_id' => $requestId,
]);
}Production practice
Contract
Set user-facing latency and capacity budgets, then tie each optimization to a measured bottleneck and success metric.
Verification
Benchmark with warm/cold caches, realistic data, concurrency, and enough duration to observe steady state and tail latency.
Operations
Watch FPM queue depth, worker saturation, OPcache health, memory, database time, external calls, and error rates together.
Common failure mode
Independent workshop
Profile and improve a slow catalog endpoint under a documented load model without changing its response contract.
Your finished workshop must include:
- Baseline flame graph and query trace
- One evidence-backed optimization with before/after percentiles
- Capacity estimate and regression performance test
Definition of done
Recap & quick check
Key takeaways
- Measure before optimizing.
- OPcache removes repeated compilation cost.
- I/O often dominates PHP web latency.
- Tail percentiles reveal user pain hidden by averages.
Quick check
1. What does OPcache retain?
2. Which metric exposes slowest common experiences?
3. What should select an optimization?
Keep the workshop: later phases deliberately build on these boundaries, so today's small example can become part of your portfolio architecture.