Way back in 2011, I created
Beryllium\CacheBundle for Symfony 2. It got a bit of traction, but superior options soon appeared, and then PSR-6 landed and promised a whole new world of caching. PSRs, or "PHP Standard Recommendations", are a group of framework interoperability interfaces provided by the PHP Framework Interoperability Group (FIG).
I wasn't exactly a fan of PSR-6.
The PSR was well-engineered, but it seemed like overkill for my projects. And on top of that, I was no longer working on the project that had needed caching in the first place.
I carved off part of the library so that I could use it as an independent component,
Beryllium\Cache, and moved on. Eventually I archived my local checkout as part of spring cleaning.
In 2019, after many years of sitting idle, a comment appeared on
Beryllium\Cache's GitHub repo. The commenter asked if it was dead/abandoned/etc. After a bit of thought, I realized that I had a current project that needed some real caching. One of my hobby sites was using a disk-based cache, which had always bothered me. I decided to revisit
Beryllium\Cache and get it trim and tidy.
I began by making PHP 7.2 the minimum version and getting the existing tests working with PHPUnit 8. Then I got rid of the "Memcache" support and implemented "Memcached" support.
Tangent: PHP is a bit odd about this, but it helps to think of "Memcached" as the latest PHP driver for the Memcache daemon. "Memcache", though still present in PHP, is kind of deprecated.
Beryllium\Cache\ClientInterface, I made all the
Client classes (
FilecacheClient, and the updated
MemcachedClient) implement PSR-16's
Psr\SimpleCache\CacheInterface. I also added a new
MemoryClient that has proven very useful for tests - it holds cache items in an array in memory, and doesn't require any external communication.
Not every client will have an efficient way to bulk-select, a feature that is part of the SimpleCache interface (e.g.,
getMultiple()). Such client classes may as well just reuse the existing get/set/delete methods. With that in mind, I created
Beryllium\Cache\Client\MultipleKeysTrait to handle the
->deleteMultiple() methods using the existing get/set/delete methods.
As part of the cleanup, I removed some Statistics-related classes that were originally being used by the FilecacheClient. They had become clutter. A more useful implementation may become clear in the future.
The concept of "safe" and
->isSafe() was also removed. These methods previously allowed client classes to do a quick check that their target was up and running - for example, the Memcache one would spend a few cycles pinging the Memcache server to ensure it was operational. The FilecacheClient still has a check like this built in, but Client classes now are advised to throw exceptions if the world doesn't seem right to them.
This new approach of adhering to the SimpleCache PSR means that I can decorate clients with anything else that adheres to the CacheInterface.
I added two new
CacheInterface wrappers that can interoperate with any PSR-16-compliant cache client:
Beryllium\Cache\Wrapper\IgnoreThrowablesWrapper catches any Throwable emitted by its wrapped client & ignores it, effectively skipping that cache client.
Beryllium\Cache\Wrapper\CascadeWrapper enables you to chain caches together and query each of them until a result is found. If backfill functionality is enabled, using
->disableBackfill(), the Cascade Wrapper will also write any cache hits to clients that previously had cache misses. This feature is disabled by default, but could be useful for hydrating an APCu cache from a shared Memcache server.
I'm happy that everything is tidied up. I integrated the cleaner library into my hobby project and things have been working great, except for an errant logging statement that ended up writing a gigabyte of "cache hit/miss" log lines. 😂 That was an easy fix, thankfully, and wasn't related to the caching library's code.
Published: March 18, 2020