cache/simple-cache-bridge
Exposes an existing PSR-6 cache pool through the PSR-16 CacheInterface, letting you reuse one pool for both standards. Install with composer require cache/simple-cache-bridge:^2.0. Supports psr/cache 3 and psr/simple-cache 2 and 3.
get/set/delete/clear plus the *Multiple variants mapped onto a CacheItemPoolInterface. That is an afternoon of internal work plus tests. "Buying" it means acquiring a transitive dependency, a supply-chain surface, and a maintenance owner outside our control for logic we could own outright. The default recommendation is build internally behind an internal seam, or use a first-party adapter — not adopt.Psr\SimpleCache\CacheInterface while our infrastructure is a PSR-6 pool (Symfony Cache adapters, legacy php-cache pools, a store whose only implementation is PSR-6). This package lets us answer "can we integrate this without re-platforming our cache layer?" — usually yes, but check the framework-native path first.expiresAfter(), no getItems() batching, no CAS. If any planned feature depends on tag-based invalidation ("purge all product-page fragments"), the bridge silently removes that capability. That is a roadmap constraint, and it must be recorded before adoption, not discovered during a launch.[READ-ONLY] split-out sub-repo with 42 stars and zero dependents tells us where the ecosystem sits: this pattern is rarely exercised. It is a weak argument for building a PSR-6-first architecture going forward, and a strong argument for treating PSR-16 as an edge adapter rather than a strategic contract.Consider it only when all of the following hold:
CacheItemPoolInterface, or a backend whose only maintained implementation is PSR-6. If the store is Laravel-native, this package is redundant: Laravel already ships Illuminate\Cache\Psr6Cache and Illuminate\Cache\Psr16Cache.Psr\SimpleCache\CacheInterface rather than Laravel's Illuminate\Contracts\Cache\Repository. If no consumer needs it, adoption is optional dependency debt.Psr\Cache\InvalidArgumentException/CacheException; PSR-16 requires the Psr\SimpleCache equivalents. A leak here turns a cache miss into an uncaught 500. Test it against a deliberately failing backend before committing.null as "use default" and 0/negative as "delete," while PSR-6 uses expiresAfter(). Misalignment shows up as silent hit-ratio drift rather than an error.setMultiple/getMultiple are almost certainly loops over single-key PSR-6 calls, multiplying Redis/Memcached round-trips. A 500-key batch becomes 500 network calls.^ ranges, no automated bumps — and name an internal owner, because the [READ-ONLY] split repo routes issues across a repository boundary that nobody upstream will triage on our timeline.Look elsewhere when:
symfony/cache's Psr16Cache instead — same abstraction, materially larger install base, better maintenance. This should be the default comparison.CACHE_DRIVER or via Cache::extend(). Both are wrong hooks: the cache manager's extension callback must return an Illuminate\Contracts\Cache\Store, not a PSR-16 instance, and resolution will fail. The supported pattern is a container binding for Psr\SimpleCache\CacheInterface plus constructor injection.For executives — the one-liner: This is a small, MIT-licensed adapter that lets code expecting the PSR-16 cache interface reuse a cache pool we already run. It is not a platform investment; it is a narrow interop shim, and the cheapest form of it is probably one we write ourselves.
The product case. Reusing an existing pool means zero data migration, zero backfill, zero dual-write — keys, TTLs, and stored values are unchanged. That reversibility is the package's strongest argument: delete the binding and consumers fall back to whatever they used before. It unlocks integrating a PSR-16-typed vendor package without re-platforming our cache layer, at an estimated cost of half a day for a spike plus one to two days end-to-end including config and a feature-flagged rollout.
The honest risk framing. Risk here is supply-side, not engineering-side: ~42 stars, zero dependents, single-organisation stewardship, release notes that point at a changelog rather than describing changes, and PHP 8.1+ / future PSR conformance unverified. There is no SLA and no vendor — we own support the moment we ship it. Mitigation is cheap and should be budgeted, not treated as an emergency: keep the vendor class behind exactly one internal wrapper, pin an exact version, and budget one day for vendoring or a ~150-line in-house reimplementation if upstream goes dormant.
What we are giving up, stated up front. PSR-16 is the lowest common denominator: tags, per-item expiry, and batch reads do not survive the crossing. Any product feature that depends on tag-based invalidation loses that capability. State this as a roadmap constraint now, not as an incident later.
Recommended path for engineering. Run a half-day spike that asserts PSR-16 conformance on single-key ops, batch ops, TTL edge cases (null, 0, negative), and exception translation against a failing backend. Wrap it in an internal factory/binding so no application code names the vendor class. Add hit/miss counters and a latency histogram before canarying on one low-risk read-through consumer for a full eviction cycle. Promote only if hit ratio and p95 are flat against the incumbent; otherwise delete the binding — the cost of reversing is near zero, which is exactly why the spike is worth doing.
The organizational cost worth naming. The technical ramp-up is half a day. The real cost is teaching the team when to reach for this (legacy PSR-6 pool, PSR-16-typed consumer) versus Laravel's native repository (almost everything else). Left undocumented, this becomes a second, parallel caching idiom in the codebase — a larger long-term cost than the dependency itself. Ship it with a one-paragraph "use this only if…" note in the architecture decision record.
How can I help you explore Laravel packages today?