databases storage and caching

Memcached Overview

Memcached is a simple in-memory key-value cache. PHP applications use it to avoid repeating expensive work, such as database queries, rendered fragments, API lookups, or configuration reads.

Memcached is intentionally narrow: it is mainly a cache. Unlike Redis, it is not commonly used as a queue, stream, lock store, or general data-structure server. That simplicity can be a strength when all the application needs is fast temporary cache storage.

Cache, Not Source Of Truth

Memcached values can disappear because they expire, because memory fills up, or because the server restarts. Application code must treat Memcached as optional acceleration, not as the only copy of important business data.

The usual flow is:

  1. Build a cache key.
  2. Try to read the value from Memcached.
  3. If it exists, use it.
  4. If it does not exist, load from the source of truth.
  5. Store the value in Memcached with a TTL.
PHP example
<?php

declare(strict_types=1);

function productCacheKey(int $productId): string
{
    return 'product:' . $productId;
}

echo productCacheKey(123) . PHP_EOL;

// Prints:
// product:123

TTLs

A TTL, or time to live, controls how long a value may remain in cache. Most Memcached entries should have an expiry.

PHP example
<?php

declare(strict_types=1);

$cacheWrite = [
    'key' => 'product:123',
    'ttl_seconds' => 600,
    'value' => ['id' => 123, 'name' => 'Keyboard'],
];

print_r($cacheWrite);

// Prints:
// [ttl_seconds] => 600

Short TTLs reduce stale data but increase cache misses. Long TTLs reduce repeated work but may serve old data for longer. Choose TTLs based on the cost of recomputing and how quickly the data changes.

Cache Misses

A cache miss is normal. Code should not treat it as an error.

PHP example
<?php

declare(strict_types=1);

function cachePlan(bool $hit): string
{
    return $hit ? 'use cached value' : 'load from database and cache result';
}

echo cachePlan(true) . PHP_EOL;
echo cachePlan(false) . PHP_EOL;

// Prints:
// use cached value
// load from database and cache result

If a cache miss breaks the feature, the cache is being used as a source of truth.

Memcached vs Redis

Both Memcached and Redis can cache values, but they are not identical.

Memcached is a good fit when:

  • The application needs simple temporary key-value caching.
  • Losing cached values is acceptable.
  • The team wants a small cache-specific service.

Redis may be a better fit when:

  • The application also needs queues, locks, counters, sessions, or richer data structures.
  • The framework already standardises on Redis.
  • Operational tooling expects Redis.

Use the technology your project can operate safely, not only the one that looks faster in a benchmark.

Key Design

Use clear namespacing and include enough information to avoid collisions.

PHP example
<?php

declare(strict_types=1);

function categoryPageCacheKey(int $categoryId, int $page): string
{
    return 'catalog:category:' . $categoryId . ':page:' . $page;
}

echo categoryPageCacheKey(7, 2) . PHP_EOL;

// Prints:
// catalog:category:7:page:2

Avoid putting secrets or personal data directly into cache keys. Keys are often visible in logs or diagnostics.

Failure Behaviour

If Memcached is unavailable, many applications can bypass it and read from the database. That may be slower, but correct.

However, a cache outage can still overload the database if every request suddenly recomputes expensive data. Production systems need monitoring for cache hit rate, evictions, memory usage, and connection failures.

What To Check

Before moving on, make sure you can:

  • Explain what Memcached is used for in PHP applications.
  • Treat Memcached as cache, not source-of-truth storage.
  • Design predictable cache keys.
  • Use TTLs deliberately.
  • Handle cache misses normally.
  • Explain when Redis might be a better fit.
  • Describe what should happen if Memcached is unavailable.

Practice

Practice: Design Memcached Behaviour

Write a small PHP example that models Memcached cache behaviour for a product lookup.

Requirements

  • Build a predictable product cache key.
  • Include a TTL.
  • Model a cache hit and cache miss.
  • Identify the database as the source of truth.
  • Include a note about what should happen if Memcached is unavailable.
  • Mention one reason Redis might be chosen instead.
Show solution

This solution models the cache flow without needing a Memcached server.

PHP example
<?php

declare(strict_types=1);

function productCacheKey(int $productId): string
{
    return 'catalog:product:' . $productId;
}

function productCachePlan(int $productId, bool $cacheHit, bool $memcachedAvailable): array
{
    if (!$memcachedAvailable) {
        return [
            'key' => productCacheKey($productId),
            'source' => 'database',
            'action' => 'skip Memcached and load from the database',
            'ttl_seconds' => null,
        ];
    }

    if ($cacheHit) {
        return [
            'key' => productCacheKey($productId),
            'source' => 'memcached',
            'action' => 'return cached product',
            'ttl_seconds' => 600,
        ];
    }

    return [
        'key' => productCacheKey($productId),
        'source' => 'database',
        'action' => 'load product, store in Memcached, then return it',
        'ttl_seconds' => 600,
    ];
}

$examples = [
    productCachePlan(123, true, true),
    productCachePlan(123, false, true),
    productCachePlan(123, false, false),
];

foreach ($examples as $example) {
    echo json_encode($example, JSON_THROW_ON_ERROR) . PHP_EOL;
}

// Prints:
// {"key":"catalog:product:123","source":"memcached","action":"return cached product","ttl_seconds":600}
// {"key":"catalog:product:123","source":"database","action":"load product, store in Memcached, then return it","ttl_seconds":600}
// {"key":"catalog:product:123","source":"database","action":"skip Memcached and load from the database","ttl_seconds":null}

The database remains the source of truth. Redis might be chosen instead if the application also needs queues, locks, counters, or richer data structures.