cakephp/cache
Cache is CakePHP's caching library, offering a consistent API for storing and retrieving data across backends such as File, Redis, Memcached, APCu, and Array. It supports PSR-16 simple caching, flexible configuration, and easy integration with CakePHP applications.
cakephp/cache is the caching layer extracted from CakePHP. It works standalone, but it's designed around CakePHP's conventions (a static Cache facade plus pluggable engine classes), and it depends on cakephp/core for the config registry. The 50-star count reflects that this repo is a read-only split, not the project's actual adoption—don't mistake it for an unproven library.
composer require cakephp/cache
Look first at:
Cake\Cache\Cache — the static facade you'll call (write, read, remember, delete, clear, add, increment).Cake\Cache\Engine\* — the backends: FileEngine, RedisEngine, MemcachedEngine, ApcuEngine, ArrayEngine, NullEngine.Cake\Cache\CacheEngine / CacheEngineInterface — the base class and contract if you need to write your own engine.There is no config file, service provider, or console command: you register configs yourself before first use.
use Cake\Cache\Cache;
use Cake\Cache\Engine\FileEngine;
Cache::setConfig('default', [
'className' => FileEngine::class,
'path' => storage_path('framework/cache/cakephp'),
'prefix' => 'acme_',
'duration' => '+1 hour',
]);
First real use case—read-through caching of an expensive result:
$report = Cache::remember('report:'.$id, fn () => $this->buildReport($id), 'default');
remember() is available in 4.3+ and is the method you'll reach for 90% of the time. In a Laravel app, register setConfig() in a service provider's register() (or boot()) so config lands before anything reads a key, and swap the engine to ArrayEngine in tests.
Use named configs per workload, not one global config. The engine registry is keyed by name, so you can mix backends freely:
Cache::setConfig('hot', [
'className' => \Cake\Cache\Engine\RedisEngine::class,
'host' => config('database.redis.cache.host'),
'port' => (int) config('database.redis.cache.port'),
'database' => 1,
'prefix' => 'acme_'.config('app.env').'_',
'duration' => 3600,
]);
Cache::setConfig('array', ['className' => \Cake\Cache\Engine\ArrayEngine::class]);
Choose: FileEngine for single-host local storage; RedisEngine/MemcachedEngine for multi-node; ApcuEngine for per-server opcode cache; ArrayEngine for request-scoped/tests; NullEngine to silently disable caching in local dev.
Wrap the facade in your own class. The static API is awkward to inject and mock. A small ReportCache class that takes a config name keeps testability while still using Cache::remember() underneath.
Single-flight / locks with add(). add() only writes when the key is absent, which is the closest thing to set-if-not-exists. Treat it as best-effort per engine and verify behavior before using it as a mutex.
Bulk operations. writeMany(), readMany(), and deleteMany() cut round-trips when hydrating a page's worth of values. Inspect the shape of misses in readMany() (it differs from read()) before relying on it.
Group invalidation instead of key hunting. Configure 'groups' => ['reports'] and clear with Cache::clearGroup('reports', 'default') when a write invalidates a family of keys. File, Redis, and Memcached engines support groups; verify support on the engine you pick before building invalidation around it.
Counters. increment()/decrement() for rate limits and lightweight stats—much cheaper than read-modify-write.
Prefix per app and environment. On shared Redis/Memcached, a unique prefix is the only thing separating your keys from another app's.
Warm after deploy. A small command that calls the same read-through paths post-deploy avoids a cold-cache stampede on the first traffic spike.
read() returns false on miss. Caching the literal false (or returning null from a remember() callback) is ambiguous and can cause repeated recomputation. Store a sentinel wrapper such as ['value' => false].remember() has no stampede protection. Concurrent misses all run the callable. Pair it with add()-based locking where that matters.setConfig('default', ...) after 'default' has already been used won't replace the live engine. Call Cache::drop('default') first, or configure before any read. In tests, do this in setUp().clear() is engine-specific and dangerous. Memcached's clear() is a server flush(); on some Redis versions clear() operates at database scope rather than prefix scope. Never point it at a shared production instance—verify on your version in a scratch DB first.Cache. Serialization (PHP serialize vs. Laravel's own format), prefixes, and TTL semantics all differ. Two libraries pointing at one Redis DB will produce unreadable payloads./, :, and very long keys. Build keys through one helper.path must exist and be writable; enable 'lock' => true for concurrent writers; set mask/dirMask for permissions; expired files are removed by probabilistic GC (Cache::gc('default') forces it). On NFS or shared volumes, use Redis instead. Its 'debug' => true option appends HTML comments to cached output.strtotime()-parsable strings ('+1 hour'). Semantics of 0 differ by engine; don't assume "forever"—check the engine source.false rather than throwing by default. If cache availability is part of your SLO, wrap calls and emit your own metrics.className, not driver. RedisEngine wants host/port/password/database/prefix/timeout/persistent/serialize; MemcachedEngine wants servers (host/port/weight), compress, username, password, serializer, options.symfony/cache's adapters), this package isn't it; wrap it or use a standards-based implementation.cakephp/cakephp under src/Cache. Match the package major (4.x/5.x) to your PHP version and, if you're inside CakePHP, to the framework.Cache::configured() lists registered names; Cache::getConfig('default') and Cache::engine('default') inspect a live config. On Redis, MONITOR is the fastest way to see whether the package or your own code is issuing the writes you expect.How can I help you explore Laravel packages today?