April 27th, 2026

[13.x] Laravel Framework: Implement CanFlushLocks on NullStore and MemoizedStore

[13.x] Laravel Framework: Implement CanFlushLocks on NullStore and MemoizedStore
Sponsored by
Table of Contents

@sumaiazaman merged PR #59850 into laravel/framework for the 13.x branch, implementing the CanFlushLocks interface on NullStore and MemoizedStore.


The Gap

After #59738 added CanFlushLocks to FailoverStore, every major cache lock provider implemented both LockProvider and CanFlushLocks except two. NullStore and MemoizedStore both implemented LockProvider but were missing CanFlushLocks, which meant Cache::supportsFlushingLocks() returned false for those stores even though the other five (Redis, File, Array, Database, Failover) all returned true.

Store Before After
NullStore LockProvider only LockProvider, CanFlushLocks
MemoizedStore LockProvider only LockProvider, CanFlushLocks

NullStore: A Stateless No-Op

NullStore uses NoLock internally, which never persists anything. There is nothing to flush, so flushLocks() simply returns true and hasSeparateLockStore() returns false.

1// NullStore now satisfies CanFlushLocks
2$store = Cache::store('null');
3 
4$store->flushLocks(); // returns true, no-op
5$store->hasSeparateLockStore(); // returns false

MemoizedStore: Delegates to the Underlying Store

MemoizedStore wraps another store, so its CanFlushLocks implementation passes the call through. If the underlying store implements CanFlushLocks, flushLocks() delegates to it. If it does not, a BadMethodCallException is thrown, consistent with how lock() and restoreLock() already handle unsupported underlying stores.

1// Underlying store supports flushing locks
2$store = Cache::store('memoized'); // backed by Redis, Array, etc.
3 
4$store->flushLocks(); // delegates to the underlying store
5$store->hasSeparateLockStore(); // delegates to the underlying store
6 
7// Underlying store does not support CanFlushLocks
8$store->flushLocks(); // throws BadMethodCallException

Test Coverage

@sumaiazaman added five new tests covering both stores:

  • CacheNullStoreTest::testLocksCanBeFlushed
  • CacheNullStoreTest::testHasSeparateLockStore
  • CacheMemoizedStoreTest::testLocksCanBeFlushedWhenUnderlyingStoreSupportsIt
  • CacheMemoizedStoreTest::testFlushLocksThrowsWhenUnderlyingStoreDoesNotSupportIt
  • CacheMemoizedStoreTest::testHasSeparateLockStoreDelegatestoUnderlyingStore

Anyone writing code that calls Cache::supportsFlushingLocks() and branching on the result can now rely on consistent behavior across all built-in cache stores, including null and memoized configurations.

If you enjoyed this article, please consider supporting our work for as low as $5 / month.

Sponsor
Marian Pop

Written by

Marian Pop

Writing and maintaining @LaravelMagazine. Host of "The Laravel Magazine Podcast". Pronouns: vi/vim.

Comments

Stay Updated

Subscribe to our newsletter

Get latest news, tutorials, community articles and podcast episodes delivered to your inbox.

Weekly articles
We send a new issue of the newsletter every week on Friday.
No spam
We'll never share your email address and you can opt out at any time.