PHP Clients for Redis vs Memcached
PHP's cache-client situation is shaped by the FPM worker model: each request creates a fresh PHP process, and persistent connections become essential. Both Redis and Memcached have C-extension clients that handle this well; Predis exists for environments where extensions are not an option.
The FPM persistent-connection problem
PHP's typical execution model is request-scoped: each HTTP request lands in a fresh PHP process state (or rather, a recycled FPM worker that may have been used by earlier requests for different users). If every request opens a new Redis or Memcached TCP connection, the overhead dominates the actual cache operation. A TCP handshake is 1-3ms by itself; for a cache call that should take sub-millisecond, that is the entire request budget.
The solution is persistent connections: connections are pooled at the PHP worker level, kept open across requests, and reused. Both PhpRedis and the Memcached extension support this via $redis->pconnect() and new Memcached('persistent_id') respectively. The pool is per-FPM-worker, so with 50 FPM workers you have 50 long-lived Redis connections, which is fine for Redis but can be wasteful for Memcached (which traditionally expects many short-lived connections, though it handles many long-lived ones fine too).
Predis cannot use truly persistent connections in the same way because it is pure PHP and the connection lifetime is bound to the request. This is why Predis is noticeably slower for high-traffic workloads: every request pays the TCP-setup cost. For development and low-traffic production sites the difference is invisible; for high-throughput production sites with cache-heavy templates (typical WordPress, Drupal, Magento, Laravel apps), the PhpRedis advantage is large.
Side-by-side: a Laravel cache call
// config/cache.php
'default' => env('CACHE_DRIVER', 'redis'),
// In a controller
use Illuminate\Support\Facades\Cache;
$value = Cache::remember(
'user:' . $userId . ':profile',
3600,
fn () => User::find($userId)->profile
);
// Raw Redis for sorted set
use Illuminate\Support\Facades\Redis;
Redis::zadd('leaderboard', 1850, 'user:' . $userId);
$top10 = Redis::zrevrange('leaderboard', 0, 9, 'WITHSCORES');// config/cache.php
'default' => env('CACHE_DRIVER', 'memcached'),
// Same Cache facade, same API
$value = Cache::remember(
'user:' . $userId . ':profile',
3600,
fn () => User::find($userId)->profile
);
// No equivalent for sorted sets.
// Drop down to raw client:
$mc = Cache::store('memcached')->getStore()->getMemcached();
// Memcached has no zadd, no zrevrange.
// You must use Redis for these patterns.Symfony and Doctrine Cache integration
Symfony's Cache component provides a PSR-6 and PSR-16 compatible cache abstraction with backend adapters for Redis and Memcached. Symfony\Component\Cache\Adapter\RedisAdapter works with both PhpRedis and Predis. MemcachedAdapter wraps the Memcached extension.
The interesting Symfony addition is RedisTagAwareAdapter, which adds tag-based invalidation on top of Redis sets. You attach tags to cached items, then invalidate by tag and the adapter deletes all items carrying that tag. This is impossible on Memcached because Memcached has no set type to back the reverse index. For applications with complex invalidation patterns, the tag-aware Redis adapter is a real reason to choose Redis over Memcached.
Doctrine ORM's second-level cache uses the same Symfony Cache backends, so the same engine choice applies to entity-level caching. For production Doctrine workloads with read-heavy queries, the cache layer (often Redis in 2026) is what makes the application performant; without it, every request hits the database for the same data.
WordPress, Drupal, Magento patterns
WordPress uses an object cache abstraction with drop-in plugins providing the actual cache backend. Redis Object Cache by Till Kruss is the most popular Redis option and supports both PhpRedis and Predis. For Memcached, the historic standard was the W3 Total Cache plugin's memcached driver or the standalone memcached-redux. Both engines work for WordPress; Redis tends to be chosen for new high-traffic sites because it also handles transient storage, page cache, and object cache in one place.
Drupal's caching infrastructure is the most cache-heavy of the three. Drupal 10 ships with three cache backends (database default, Memcache module, Redis module). Acquia Cloud (Drupal hosting) recommends Redis for new sites and Memcache for legacy compatibility. Pantheon (another Drupal/WordPress host) bundles Redis with all paid plans and does not offer Memcached.
Magento (e-commerce, PHP-based) supports both engines but the Magento 2 documentation pushes Redis as the recommended cache backend for session storage and page caching. Magento's page-cache layer is one of the heaviest cache workloads in PHP-land (a typical product page involves dozens of cache lookups for layout fragments, prices, stock levels, customer-segment-specific blocks). PhpRedis with persistent connections is the canonical Magento production setup.
FAQ
PhpRedis or Predis?
PhpRedis (C extension) for production: faster, lower memory, supports persistent connections critical for FPM workers. Predis (pure PHP) for dev environments where you cannot install C extensions, or for shared hosting. Performance difference is meaningful: PhpRedis is typically 2-3x faster on hot paths.
Memcache or Memcached extension?
Memcached (with the 'd') is the modern PECL extension wrapping libmemcached. Memcache (no 'd') is the older PECL extension, less feature-complete. Use Memcached; the older Memcache extension is effectively deprecated since 2018.
Laravel cache backend?
Laravel supports Redis (via PhpRedis or Predis) and Memcached as cache, queue, and session backends out of the box. config/cache.php has driver entries for both. Redis is the more common production choice because Laravel Horizon (queue dashboard) requires it and Laravel sessions benefit from Redis persistence.
Symfony cache adapters?
Symfony Cache component ships adapters for Redis (RedisAdapter, RedisTagAwareAdapter for tag-based invalidation) and Memcached (MemcachedAdapter). The tag-aware variant is Redis-only because Memcached cannot do set-based reverse indexing.
WordPress object cache?
WordPress can use either via drop-in object cache plugins. Redis Object Cache (by Till Kruss) is the most popular Redis option. W3 Total Cache and WP Super Cache support both Redis and Memcached. For Memcached on WordPress, the official memcached-redux plugin is the canonical choice.