PHP
Summary - Performance
Build an optimized data service with OPcache, benchmarks and eager loading.
Summary - Performance
This group covered four pillars of PHP performance: OPcache removed the compilation cost with a bytecode cache; profiling tools revealed bottlenecks by call count and time; memory_get_usage and the Spl data structures let you watch memory consumption; microtime-based benchmarks compared two approaches.
You fixed the N+1 problem with eager loading and used lazy initialization to skip unnecessary work. Performance work is measure first, change second — intuition misleads.
A combined performance approach
In a real scenario you combine the four tools: first check OPcache with opcache_get_status; then time the comparison with microtime; watch memory spikes with memory_get_peak_usage; if the database shows N+1, switch to eager loading.
Changing a step without measuring leaves optimization to intuition; deciding after a measurement is the professional move.
Exercise OPcache, benchmark and eager loading combined
Start with $start = microtime(true). Get the OPcache status with $opcache_ok = function_exists('opcache_get_status') && opcache_get_status(false) !== false;. The $posts and $authors arrays below are ready. In a foreach print echo $post['title'] . ':' . $authors[$post['author_id']] . "\n"; for each post. Compute $end = microtime(true) and $elapsed = $end - $start. Print echo ($opcache_ok ? "1\n" : "0\n"); and echo count($posts) . "\n";.
Show example solution
' . $authors[$post['author_id']] . "\n"; } $end = microtime(true); $elapsed = $end - $start; echo ($opcache_ok ? "1\n" : "0\n"); echo count($posts) . "\n";.
Example solution:
<?php
$start = microtime(true);
$opcache_ok = function_exists('opcache_get_status') && opcache_get_status(false) !== false;
$posts = [
['id' => 1, 'title' => 'A', 'author_id' => 10],
['id' => 2, 'title' => 'B', 'author_id' => 20],
];
$authors = [10 => 'Ayşe', 20 => 'Deniz'];
foreach ($posts as $post) {
echo $post['title'] . ':' . $authors[$post['author_id']] . "\n";
}
$end = microtime(true);
$elapsed = $end - $start;
echo ($opcache_ok ? "1\n" : "0\n");
echo count($posts) . "\n";
Exercise FileCache with an SplStack
Write a FileCache class with public SplStack $keys;; in __construct assign $this->keys = new SplStack();. The set(string $key): void method calls $this->keys->push($key). Create $cache = new FileCache();. Call set('user_1'), set('user_2'), set('user_3'). Print echo $cache->keys->count() . "\n";, echo $cache->keys->pop() . "\n";, echo $cache->keys->count() . "\n";.
Show example solution
void { $this->keys->push($key); } }. $cache = new FileCache(); $cache->set('user_1'); $cache->set('user_2'); $cache->set('user_3'); echo $cache->keys->count() . "\n"; echo $cache->keys->pop() . "\n"; echo $cache->keys->count() . "\n";.
Example solution:
<?php
class FileCache {
public SplStack $keys;
public function __construct() {
$this->keys = new SplStack();
}
public function set(string $key): void {
$this->keys->push($key);
}
}
$cache = new FileCache();
$cache->set('user_1');
$cache->set('user_2');
$cache->set('user_3');
echo $cache->keys->count() . "\n";
echo $cache->keys->pop() . "\n";
echo $cache->keys->count() . "\n";
Test yourself
-
Which approach cuts queries the most?
- Calling each item separately with lazy loading
- Calling memory_get_usage
- Loading all relations in one query with eager loading
- Using a plain array instead of SplStack
Show answer
Loading all relations in one query with eager loading — Correct. Eager loading collapses N+1 into one query and cuts the count the most.
Next lesson: password_needs_rehash()