Understanding PHP Caching Layers

Caching in PHP can be implemented at multiple levels: opcode, object, and HTTP caching. Each layer serves a different purpose and can be used in combination to optimize performance.

Opcode Caching

Opcode caching stores precompiled script bytecode in memory, eliminating the need for PHP to load and parse scripts on each request. PHP 7+ comes with OPcache enabled by default in most production setups. Ensure it is configured in php.ini:

opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000

Object Caching

Object caching is ideal for storing complex data structures or results of expensive computations. Tools like Memcached or Redis are commonly used for this purpose.

Example using Redis:

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

$key = 'user_profile_123';
if (!$redis->exists($key)) {
    $profile = fetchUserProfileFromDB(123);
    $redis->setex($key, 3600, json_encode($profile));
} else {
    $profile = json_decode($redis->get($key), true);
}

This example retrieves a user profile from a database only if it is not already cached in Redis, which expires in 1 hour.


HTTP Caching with Headers

HTTP caching allows you to reduce server load and latency by instructing clients and intermediaries (like CDNs) to cache responses. PHP can manage this via headers:

$cacheDuration = 3600; // 1 hour
header('Cache-Control: public, max-age=' . $cacheDuration);
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $cacheDuration) . ' GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime(__FILE__)) . ' GMT');

For dynamic content, you can use ETag headers to enable conditional requests:

$etag = md5($content);
header("ETag: $etag");
if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] === $etag) {
    http_response_code(304);
    exit;
}

Caching in Frameworks

Modern PHP frameworks like Laravel and Symfony provide built-in caching tools that abstract away much of the complexity.

Laravel Cache Example

Laravel’s Cache facade offers a unified API for different cache backends:

use Illuminate\Support\Facades\Cache;

$user = Cache::remember('user-profile-123', 60, function () {
    return DB::table('users')->where('id', 123)->first();
});

This code will execute the closure and cache the result for 60 minutes if it’s not already present.

Cache Tags in Laravel

Cache tags allow you to group related items and invalidate them together:

Cache::tags(['user', '123'])->put('profile', $userProfile, 60);

// Later, when the user updates their profile
Cache::tags(['user', '123'])->flush();

Caching Best Practices

StrategyUse CaseCache DurationNotes
Opcode cachingPHP scriptsProcess lifeUse OPcache
Object cachingExpensive data processingMinutes-hoursUse Redis/Memcached
HTTP cachingStatic assets, public pagesMinutes-hoursUse Cache-Control and ETag
Fragment cachingParts of dynamic pagesMinutesUse ob_start() or framework tools
Query/result cachingRepeated database queriesMinutesUse PDO or ORM caching

Ensure cache keys are unique and follow a consistent naming convention, such as user-profile-{id} or blog-post-{slug}. Also, always implement proper cache invalidation strategies to avoid stale data.


Learn more with useful resources