← Home ← Codex ← DEBT
Browse by Category
+ added · updated 7d
← Back to glossary

Caching Strategies

Performance PHP 7.0+ Intermediate
debt(d7/e5/b5/t7)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). The detection_hints.tools field is not specified. Common caching mistakes — missing key namespacing, caching inside transactions, cache stampede, missing TTL — produce silent bugs visible only in runtime conditions (stale data served to wrong users, post-rollback inconsistency). No standard linter or SAST tool reliably catches these patterns; they surface through code review or production monitoring.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix shows a single cache-aside call is easy to add, but the common_mistakes reveal that fixing systemic issues (key namespacing across all call sites, removing cache calls from all transactions, applying per-entity TTL policies, adding stampede protection) requires changes across multiple service and repository classes rather than a single one-line swap.

b5 Burden Structural debt — long-term weight of choosing wrong

Closest to 'persistent productivity tax' (b5). Caching strategy applies to both web and cli contexts and touches any data-access layer. Once a caching pattern is in place — especially if key naming conventions, TTL policies, or cache population logic are inconsistent — every future feature that reads or writes cached data must be aware of and conform to those choices. It slows many work streams but is not fully architectural in the b7/b9 sense.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7). The misconception field lists multiple serious traps: 'caching always improves performance' contradicts real-world outcomes; caching without user/tenant namespacing silently leaks data between users; caching inside transactions produces inconsistent state on rollback; no TTL means perpetually stale data. These contradict intuitive expectations and parallel patterns from simpler use cases elsewhere, making t7 appropriate — they are documented gotchas that competent developers frequently get wrong on first encounter.

About DEBT scoring →

Also Known As

cache-aside write-through write-behind read-through lazy loading cache cache invalidation

TL;DR

Patterns for when and how to store and invalidate cached data — cache-aside, write-through, write-behind, and read-through each make different trade-offs between consistency, complexity, and performance.

Explanation

The four core caching strategies: Cache-aside (lazy loading) — the application checks the cache first; on a miss, loads from the database, stores in cache, returns the result. The application controls all cache interactions. Write-through — writes go to both the cache and the database synchronously; reads always hit cache. Strong consistency, higher write latency. Write-behind (write-back) — writes go to cache immediately and to the database asynchronously; fast writes, risk of data loss if cache fails before persisting. Read-through — the cache itself loads from the database on a miss; the application only ever talks to the cache layer. In PHP, cache-aside with Redis or Memcached is the most common pattern. Cache invalidation strategies: TTL-based (expire after N seconds), event-based (invalidate on write), and pattern-based (purge all keys matching a prefix). The hardest problem in caching is stale data — knowing when cached data no longer reflects the source of truth.

Watch Out

Cache-aside patterns create a thundering herd problem: if a cached key expires under high traffic, all concurrent requests miss the cache, hammer the database simultaneously to repopulate it, and can trigger cascading failures — mitigated by probabilistic early expiration or locking during cache load.

Common Misconception

Caching always improves performance. Poorly implemented caching introduces bugs worse than the performance problem it was meant to solve. Caching user-specific data without proper key namespacing leaks data between users. Caching without a TTL produces stale data that never refreshes. Caching inside a transaction produces incorrect data if the transaction rolls back. Measure first — caching premature to a performance diagnosis adds complexity without solving the actual bottleneck.

Why It Matters

Caching is the most impactful single change for read-heavy PHP applications. A product page querying 12 database tables on every request scales to hundreds of requests per second with a 60-second cache; without caching it falls over at dozens. The cache-aside pattern with Redis is implementable in under 30 lines of PHP and immediately reduces database load by the cache hit ratio. Proper TTL and invalidation strategy choice prevents the stale data bugs that make developers distrust their cache and flush it manually.

Common Mistakes

  • Not namespacing cache keys by user or tenant — global keys like 'user_profile' serve the same cached data to all users.
  • Caching inside database transactions — if the transaction rolls back, the cached data is inconsistent with the database.
  • Using a single global TTL for all cache entries — frequently updated data needs short TTLs; rarely changing data can cache for hours.
  • Cache stampede on TTL expiry — many concurrent requests all miss and hit the database simultaneously; use probabilistic early expiry or a mutex lock on cache population.

Avoid When

  • Cache-aside on data that is written frequently — the cache is invalidated constantly and hit rate stays near zero.
  • Write-through on data that is rarely read — you pay the write overhead for cache entries that are never served.
  • Caching user-specific data in a shared cache without namespacing keys — data bleeds between users.
  • Caching without a TTL — stale entries accumulate and are never evicted.

When To Use

  • Cache-aside for read-heavy data that changes infrequently and tolerable staleness exists.
  • Write-through for data that is written and then immediately read, where cache miss after write is unacceptable.
  • Read-through when the application should never query the DB directly — the cache layer owns all reads.
  • Write-behind (write-back) for high-write workloads where batching DB writes improves throughput.

Code Examples

✗ Vulnerable
// No caching — hits database on every request
class ProductController {
    public function show(int $id): array {
        // Expensive query on every page load
        return $this->db->query(
            'SELECT p.*, c.name as cat, AVG(r.score) as rating
             FROM products p
             JOIN categories c ON p.cat_id = c.id
             LEFT JOIN reviews r ON r.product_id = p.id
             WHERE p.id = ?
             GROUP BY p.id', [$id]
        )->fetch();
    }
}
✓ Fixed
// Cache-aside with Redis — database hit only on miss
class ProductController {
    public function show(int $id): array {
        $key    = 'product:' . $id;
        $cached = $this->redis->get($key);
        if ($cached) return json_decode($cached, true);

        $product = $this->db->query('...expensive query...', [$id])->fetch();
        $this->redis->setex($key, 3600, json_encode($product)); // 1hr TTL
        return $product;
    }

    public function update(int $id, array $data): void {
        $this->db->query('UPDATE products SET ...', $data);
        $this->redis->del('product:' . $id); // invalidate on write
    }
}

Added 23 Mar 2026
Edited 15 Jun 2026
Views 76
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 1 ping T 1 ping F 0 pings S 4 pings S 3 pings M 0 pings T 1 ping W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 2 pings F 0 pings S 0 pings S 1 ping M 0 pings T 0 pings W
No pings yet today
No pings yesterday
Amazonbot 16 Perplexity 11 Scrapy 8 Google 7 Ahrefs 4 SEMrush 4 Bing 4 ChatGPT 3 Meta AI 3 Claude 1 PetalBot 1
crawler 56 crawler_json 6
DEV INTEL Tools & Severity
🔵 Info ⚙ Fix effort: Medium
⚡ Quick Fix
Implement cache-aside: $data = $cache->get($key) ?? tap($db->find($id), fn($v) => $cache->set($key, $v, 3600)) — check cache, populate on miss, set TTL
📦 Applies To
PHP 7.0+ web cli


✓ schema.org compliant