Mnemosyne - PHP Attribute-based Caching Library
Mnemosyne is a powerful and flexible caching library for PHP 8.0+ that uses attributes to simplify cache management. It provides automatic caching and invalidation based on method attributes, making it easy to add caching to your application.
Features
-
Attribute-based caching configuration
-
Automatic cache key generation
-
Parameter-based cache keys with interpolation
-
Automatic and manual cache invalidation
-
Cache tags for group invalidation
-
PSR-16 (SimpleCache) compatibility
-
Flexible cache key templates
-
Smart serialization handling:
- Automatic serialization of complex objects
- Optional raw storage for simple data types
- Full control over serialization behavior
Installation
composer require cmatosbc/mnemosyne
Usage
To use Mnemosyne in your classes, you must:
1. Use the CacheTrait
in your class
2. Inject a PSR-16 compatible cache implementation
3. Apply the Cache
attribute to methods you want to cache
Basic Usage
use Mnemosyne\Cache;
use Mnemosyne\CacheTrait;
use Psr\SimpleCache\CacheInterface;
class UserService
{
use CacheTrait; // Required to enable caching functionality
public function __construct(CacheInterface $cache)
{
$this->cache = $cache;
}
#[Cache(ttl: 3600)]
public function getUser(int $id): array
{
return $this->cacheCall('doGetUser', func_get_args());
}
private function doGetUser(int $id): array
{
// Expensive database query here
return ['id' => $id, 'name' => 'John Doe'];
}
}
Serialization Control
The Cache
attribute allows you to control how values are stored in cache:
class UserService
{
use CacheTrait;
// Automatically serialize complex objects
#[Cache(key: 'user:{id}', ttl: 3600, serialize: true)]
public function getUser(int $id): User
{
return $this->cacheCall('doGetUser', func_get_args());
}
// Store simple arrays without serialization
#[Cache(key: 'users:list', ttl: 3600, serialize: false)]
public function getUsersList(): array
{
return $this->cacheCall('doGetUsersList', func_get_args());
}
}
Custom Cache Keys
class UserService
{
use CacheTrait;
#[Cache(key: 'user:{id}', ttl: 3600)]
public function getUser(int $id): array
{
return $this->cacheCall('doGetUser', func_get_args());
}
#[Cache(key: 'users:dept:{deptId}:status:{status}', ttl: 3600)]
public function getUsersByDepartment(int $deptId, string $status): array
{
return $this->cacheCall('doGetUsersByDepartment', func_get_args());
}
}
Cache Invalidation
Automatic Invalidation
class UserService
{
use CacheTrait;
#[Cache(
key: 'user:{id}',
ttl: 3600
)]
public function getUser(int $id): array
{
return $this->cacheCall('doGetUser', func_get_args());
}
#[Cache(invalidates: ['user:{id}'])]
public function updateUser(int $id, array $data): void
{
$this->cacheCall('doUpdateUser', func_get_args());
}
#[Cache(
key: 'user:profile:{id}',
ttl: 3600,
invalidates: ['user:{id}', 'users:dept:{deptId}:status:active']
)]
public function updateProfile(int $id, int $deptId): array
{
return $this->cacheCall('doUpdateProfile', func_get_args());
}
}
Manual Invalidation
class UserService
{
use CacheTrait;
public function forceRefresh(int $userId): void
{
$this->invalidateCache("user:$userId");
// Or invalidate multiple keys:
$this->invalidateCacheKeys([
"user:$userId",
"user:profile:$userId"
]);
}
}
Cache Tags
Cache tags allow you to group related cache entries and invalidate them together. This is useful for managing cache dependencies and bulk invalidation.
class UserService
{
use CacheTrait;
#[Cache(
key: 'user:{id}',
ttl: 3600,
tags: ['user', 'user-{id}']
)]
public function getUser(int $id): array
{
return $this->cacheCall('doGetUser', func_get_args());
}
#[Cache(
key: 'user:profile:{id}',
ttl: 3600,
tags: ['user', 'user-{id}']
)]
public function getUserProfile(int $id): array
{
return $this->cacheCall('doGetUserProfile', func_get_args());
}
public function updateUser(int $id): void
{
// Invalidate all caches for a specific user
$this->invalidateTag("user-$id");
}
public function clearAllUserCaches(): void
{
// Invalidate all user-related caches
$this->invalidateTag('user');
}
}
Tags support parameter interpolation just like cache keys, allowing you to create dynamic tag names. When a tag is invalidated, all cache entries associated with that tag are automatically removed.
Best Practices
-
Split cached methods into two parts:
- A public method with the Cache attribute that handles caching
- A private method with the actual implementation
-
Use meaningful cache keys that reflect the data structure
-
Set appropriate TTL values based on data volatility
-
Use cache invalidation when data is modified
-
Consider using cache tags for group invalidation
Testing
The library includes comprehensive PHPUnit tests. Run them with:
./vendor/bin/phpunit
License
This project is licensed under the GNU General Public License v3.0 or later - see the LICENSE file for details. This means you are free to use, modify, and distribute this software, but any modifications must also be released under the GPL-3.0-or-later license.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.