psx/cache
A caching component for the PSX framework that provides a simple, consistent API for storing and retrieving cached data across different backends, helping PHP applications reduce repeated work and improve response times.
Install via composer alongside the Doctrine cache backend the package relies on:
composer require psx/cache doctrine/cache
The package is a thin bridge: it exposes a PSR-6 CacheItemPoolInterface and a PSR-16 CacheInterface that delegate to whatever Doctrine cache provider you hand it (Doctrine\Common\Cache\ArrayCache, FilesystemCache, RedisCache, etc.). Look first at the two entry classes — the PSR-6 pool and the PSR-16 simple cache — then at the Doctrine provider you intend to wrap. There is no Laravel service provider or config file, so you own the wiring.
Your first use case in a Laravel app is almost always a third-party library that type-hints against Psr\SimpleCache\CacheInterface or Psr\Cache\CacheItemPoolInterface. Bind it once in a service provider:
// app/Providers/AppServiceProvider.php
public function register(): void
{
$this->app->singleton(\Psr\SimpleCache\CacheInterface::class, function ($app) {
$doctrine = new \Doctrine\Common\Cache\FilesystemCache(
storage_path('framework/cache/psr16')
);
return new \Psx\Cache\SimpleCache($doctrine);
});
}
(Confirm the exact constructor signature against the source before shipping — the package is small enough to read end-to-end in ten minutes, which you should do given its sparse documentation.)
Container bindings for both PSR interfaces. Register PSR-16 and PSR-6 as separate singletons (or one singleton each backed by the same Doctrine provider if you want shared state). Libraries rarely need both, so bind them lazily rather than eagerly on every request.
Share a backend with Laravel's native cache by choosing the same store. If you point a FilesystemCache/RedisCache at the same Redis DB or directory that config/cache.php uses, values written by Cache::put() are not readable through PSR-16 unless the key and serialization formats match — they usually don't. Treat PSR cache as its own namespace inside the store rather than assuming interoperability.
Test with ArrayCache. Because the whole stack is Doctrine providers, your unit tests can swap in Doctrine\Common\Cache\ArrayCache with zero infrastructure. This is the single biggest practical win: PSR-compliant fakes that survive between calls inside a test without touching Redis or disk.
Reuse existing Laravel cache config to build the Doctrine provider. Add a small factory that maps your config('cache.default') to the corresponding Doctrine driver, so you get one source of truth for Redis/file/memcached credentials rather than a second copy in a service provider.
Integration tip for legacy code. If you're migrating an older library onto Laravel and it hard-depends on PSR-6 save()/getItem() semantics, wrapping a Doctrine provider here is far less invasive than rewriting call sites against Cache::get()/put().
doctrine/cache 2.x removed the driver/CacheProvider model in favor of symfony/cache. psx/cache targets the older interface, so you'll be pinned to doctrine/cache ^1.x and miss security and PHP-version fixes. For new work prefer symfony/cache's PSR-6/PSR-16 adapters wrapped around Laravel's own cache store — that path is actively maintained and avoids a dead dependency.null, int seconds, or DateInterval; Laravel treats 0 (and some drivers null) as "forever." Passing a DateInterval through this bridge to a Doctrine provider that only understands integer lifetimes will silently drop or mis-handle it. Normalize TTLs at your boundary.{}()/\@: or an empty string are illegal under PSR-16 and this implementation (correctly) rejects them. Code that worked with Cache::get(['a','b']) or object keys will throw. Guard against keys built from user input.false. PSR-16 distinguishes "not found" from a stored false. If your code does if (!$cache->get($key)) you cannot tell the difference. Use has() before get() when false is a legal value.Cache facade and this PSR cache don't share entries, cache warmup, invalidation, and Cache::forget() in one system won't affect the other. Keep an eye out for stale data during deploys if both are enabled.remember() — this is a spec-compliance adapter, not a feature-rich cache. Don't expect Laravel-like ergonomics; wrap it yourself if you need them.composer.json, read the source, and be prepared to fork if an upstream Doctrine or PHP upgrade breaks it.How can I help you explore Laravel packages today?