nael_d/cachex

Cachex: A high-performance PHP caching library with support for multiple drivers, tags, and namespaces.

Maintainers

Package info

gitlab.com/nael_d/cachex

Issues

pkg:composer/nael_d/cachex

Statistics

Installs: 18

Dependents: 1

Suggesters: 0

Stars: 0

v2.4.2 2026-05-11 02:54 UTC

README

Cachex is a completely rewritten PHP caching library featuring a singleton-based Manager, five storage drivers, a fluent interface, advanced tagging system, namespaces, encryption support, and event-driven architecture for efficient cache management.

Features

  • PHP Compatibility: Works with PHP >= 8.1.0 minimum.
  • Singleton Manager: Centralized cache management through a singleton pattern with consistent configuration across the application.
  • Fluent Interface: Build cache operations elegantly using PendingCache with method chaining for intuitive code.
  • Multi-Driver Support: Five optimized drivers for different caching strategies:
    • ArrayDriver: In-memory caching with namespace and tag indexing, configurable memory limits.
    • FilesDriver: File-based cache storage with filesystem organization and encryption support.
    • RedisDriver: High-performance Redis caching with multi-database support and encryption.
    • DatabaseDriver: SQL database-backed caching (PostgreSQL, MySQL, MSSQL) with metadata and encryption columns.
    • BlackholeDriver: No-op driver for testing and temporarily disabling cache.
  • Namespaces: Organize cache entries hierarchically with namespace and sub-namespace support to prevent key collisions.
  • Tags: Assign multiple tags to cache entries for efficient batch operations via flushByTags().
  • Encryption: Built-in AES-256-CBC encryption through HasEncryption trait across all drivers.
  • Version Control: Cache versioning for entry validation and cache busting on version mismatch.
  • Grace Periods: Retrieve expired cache entries within a grace period before complete invalidation.
  • Event System: Event-driven lifecycle with customizable listeners via on() method.
  • Presets & Memoization: Register reusable cache configurations (presets) and memoization strategies for complex operations.
  • Options Flexibility: Pass flexible options arrays to customize driver behavior for each operation.
  • Metadata: Retrieve and manage cache metadata including expiration, versioning, encryption status, and tags.

Table of Contents

Installation

Cachex is available via Composer. Install it in your project:

composer require nael_d/cachex

You can also download Cachex manually from the Releases page and require the src/ directory.

💡 For detailed version information and release notes, visit the CHANGELOG to review the development timeline and features.

Getting Started

Once installed, the Cachex package is ready to use. The main entry point is the Manager class, which operates as a singleton.

💡 The Manager class is available under the Cachex\Core namespace and should be accessed via getInstance().

use Cachex\Core\Manager;

// Get the singleton instance
$cache = Manager::getInstance();

// Configure the cache manager
$cache->config([
  'default_driver'     => 'files',
  'default_ttl'        => 300,
  'grace_period'       => 0,
  'encryption_enabled' => false,
]);

// Register drivers
$cache->addDriver('array', new ArrayDriver());
$cache->addDriver('files', new FilesDriver('.cache/'));

// Set default driver
$cache->setDefaultDriver('files');

// Start caching
$cache->set('key', 'value');

💡 Manager::getInstance() always returns the same instance, ensuring consistent state throughout your application.

Manager Configuration

The Manager maintains internal state for cache configuration. Configure it once at startup:

$cache = Manager::getInstance();

$cache->config([
  'enabled'             => true,                    // Enable/disable all caching
  'default_driver'      => 'files',                // Default driver to use
  'namespace'           => '',                      // Default namespace
  'default_ttl'         => 300,                     // Default TTL in seconds
  'grace_period'        => 0,                       // Grace period for expired entries
  'encryption_enabled'  => false,                  // Enable encryption globally
  'encryption_key'      => 'your-secret-key',      // Encryption key for AES-256-CBC
  'encryption_cipher'   => 'AES-256-CBC',          // Encryption cipher
]);

Properties

While Manager properties are private, understanding them provides insight into the library's functionality:

  • $enabled: Default is bool true. Controls whether caching logic is active.
  • $default_driver: Default is string 'files'. The active caching driver.
  • $namespace: Default is string ''. Current namespace context for cache operations.
  • $default_ttl: Default is int 300. Default time-to-live for cache entries (in seconds).
  • $grace_period: Default is int 0. Grace period extension after expiration (in seconds).
  • $encryption_enabled: Default is bool false. Global encryption status.
  • $encryption_key: Default is string ''. Key for AES-256-CBC encryption.
  • $encryption_cipher: Default is string 'AES-256-CBC'. Encryption cipher algorithm.
  • $drivers: Type is array. Registered driver instances, keyed by name.
  • $presets: Type is array. Registered cache presets for reuse.
  • $listeners: Type is array. Registered event listeners.
  • $memo_registry: Type is array. Memoization registry for tracking memoized operations.

Methods

Manager Methods

getInstance()

Returns the singleton instance of the Manager.

Usage:

$cache = Manager::getInstance();

config()

Configures the Manager with an array of settings.

Parameters:

  • array $settings: Configuration key-value pairs.

Usage:

$cache->config([
  'default_ttl'    => 600,
  'grace_period'   => 30,
  'namespace'      => 'app',
]);

enable()

Enables the caching system.

Usage:

$cache->enable();
// Caching operations are now active

disable()

Disables the caching system (safe fallback to no-op behavior).

Usage:

$cache->disable();
// All cache operations become no-ops

isEnabled()

Checks if caching is currently enabled.

Usage:

if ($cache->isEnabled()) {
    // Perform cache operations
}

addDriver()

Registers a driver with the Manager.

Parameters:

  • string $name: Driver name identifier.
  • DriverInterface $driver: Driver instance implementing DriverInterface.

Usage:

$cache->addDriver('redis', new RedisDriver(['host' => 'localhost', 'port' => 6379]));
$cache->addDriver('database', new DatabaseDriver(['connection' => $pdo]));

driver()

Sets or retrieves the active driver.

Parameters:

  • string|null $name: Optional. Driver name to set. If null, returns current driver.
  • array $options: Optional. Options to apply to the driver.

Usage:

// Set driver
$cache->driver('redis');

// Get current driver
$driver = $cache->driver();

// Switch with options
$cache->driver('redis', ['db' => 1]);

setDefaultDriver()

Sets the default driver to use.

Parameters:

  • string $name: Driver name.

Usage:

$cache->setDefaultDriver('database');

getSupportedDrivers()

Returns an array of registered driver names.

Usage:

$drivers = $cache->getSupportedDrivers();
// Returns: ['array', 'files', 'redis', 'database']

getActiveNamespace()

Retrieves the currently active namespace.

Usage:

$current = $cache->getActiveNamespace();
echo $current; // outputs: "app:users"

getGracePeriod()

Retrieves the current grace period setting.

Usage:

$grace = $cache->getGracePeriod(); // (int) 30

getEncryptionKey() / getEncryptionCipher()

Retrieve encryption configuration.

Usage:

$key    = $cache->getEncryptionKey();
$cipher = $cache->getEncryptionCipher();

Cache Operations

set()

Stores a cache entry via a PendingCache object or returns PendingCache if no value is provided.

Parameters:

  • string $key: Required. The cache key.
  • mixed $value: Optional. The value to cache.
  • array $options: Optional. Fluent options for the operation.

Returns: bool if value provided, or PendingCache object for chaining.

Usage:

// Direct set
$cache->set('user_1', $userData);

// Using PendingCache fluent interface
$cache->set('user_2')
  ->ttl(3600)
  ->tags(['users', 'active'])
  ->version('v1')
  ->set($userData);

// With options
$cache->set('secret', $data, options: ['encrypted' => true]);

get()

Retrieves a cached value by key.

Parameters:

  • string $key: Required. The cache key.
  • array $options: Optional. Options like 'grace', 'version'.
  • mixed $default: Optional. Default value if not found.

Returns: The cached value or default.

Usage:

// Basic retrieval
$user = $cache->get('user_1');

// With default
$user = $cache->get('user_1', default: []);

// With options
$data = $cache->get('key', options: ['grace' => 120]);

has()

Checks if a cache key exists and is valid.

Parameters:

  • string $key: Required. The cache key.
  • array $options: Optional. Options for checking.

Returns: bool

Usage:

if ($cache->has('user_1')) {
    $user = $cache->get('user_1');
}

key()

Returns a PendingCache object for building fluent cache operations.

Parameters:

  • string $key: The cache key.

Returns: PendingCache instance with pre-configured driver and default TTL.

Usage:

$cache->key('user_1')
  ->ttl(600)
  ->tags(['important'])
  ->namespace('users')
  ->set($userData);

hunt()

Deletes a cache entry (alias for driver's delete method).

Parameters:

  • string $key: The cache key to delete.
  • array $options: Optional. Driver-specific options.

Usage:

$cache->hunt('user_1');
$cache->hunt(['user_1', 'user_2', 'user_3']);

flush()

Flushes all cache entries (within the current namespace if set).

Parameters:

  • array $options: Optional. Driver-specific options.

Usage:

// Standard flush: Clear only the current active namespace
$cache->flush();

// Targeted flush: Clear a specific namespace
$cache->flush(['namespace' => 'cache']); // Clears 'cache' namespace

// Flush entire cache (Tsunami destruction)
$cache->flush(['all' => true]);

flushTags()

Flushes all cache entries associated with specified tags.

Parameters:

  • array $tags: The tags to flush.
  • array $options: Optional. Driver-specific options.

Usage:

// Single tag
$cache->flushTags(['users']);

// Multiple tags
$cache->flushTags(['users', 'active', 'premium']);

PendingCache Fluent Interface

The PendingCache class provides a fluent interface for building cache operations. Access it via $cache->set($key), $cache->key($key):

ttl()

Set the time-to-live for the cache entry.

Parameters:

  • int $seconds: TTL in seconds.

Usage:

$cache->key('user')->ttl(3600)->set($data);

tags()

Assign tags to the cache entry.

Parameters:

  • string|array ...$tags: Tags to assign.

Usage:

$cache->key('post')->tags('posts', 'published', 'featured')->set($post);
// Or: ->tags(['posts', 'published', 'featured'])

version()

Set the version for the cache entry (for validation).

Parameters:

  • string|null $version: Version identifier.

Usage:

$cache->key('schema')->version('v2.1.0')->set($schemaData);

grace()

Set the grace period for this cache entry.

Parameters:

  • int $seconds: Grace period in seconds.

Usage:

$cache->key('data')->grace(300)->get(); // Allows 5-min past expiration

namespace()

Set the namespace for this cache entry.

Parameters:

  • string|bool|null $namespace: Namespace string, true for default, false for no namespace.

Usage:

$cache->key('user_1')->namespace('users')->set($data);
$cache->key('global')->namespace(false)->set($data); // No namespace

encryption()

Enable or disable encryption for this entry.

Parameters:

  • bool $status: Encryption status.

Usage:

$cache->key('secret')->encryption(true)->set($sensitive);

encrypted() / plain()

Shorthand methods for encryption status.

Usage:

$cache->key('secret')->encrypted()->set($data);
$cache->key('public')->plain()->set($data);

applyOptions()

Apply flexible options for the operation.

Parameters:

  • array $options: Options to apply.

Usage:

$cache->key('data')->applyOptions(['ttl' => 600, 'encrypted' => true])->set($value);

set()

Store the value in cache.

Parameters:

  • mixed $value: Optional. Value to store (if not set in constructor).

Returns: bool - Success status.

Usage:

$cache->key('user')->ttl(3600)->tags('users')->set($userData);

get()

Retrieve the cached value.

Returns: The cached value or null.

Usage:

$user = $cache->key('user')->grace(120)->get();

has()

Check if the key exists in cache.

Returns: bool

Usage:

if ($cache->key('user')->has()) {
  // Key exists
}

pull()

Retrieve and immediately delete the cache entry.

Returns: The cached value.

Usage:

$data = $cache->key('temp')->pull(); // Get and delete

update()

Update the cached value with a new one.

Parameters:

  • mixed $newValue: New value to store.

Returns: The new value.

Usage:

$newData = $cache->key('user')->update($updatedUser);

remember()

Retrieve from cache or store a fallback value.

Parameters:

  • mixed $fallback: Callable or value to use if cache misses.

Returns: The cached or fallback value.

Usage:

$user = $cache->key('user_1')->remember(function () {
  return fetchUserFromDatabase(1);
});

storeAs()

Register this PendingCache as a reusable preset.

Parameters:

  • string $id: Preset identifier.

Usage:

$cache->key('user')
  ->ttl(3600)
  ->tags('users')
  ->namespace('app:users')
  ->storeAs('user_cache');

Event Management

on()

Register an event listener.

Parameters:

  • string $event: Event name.
  • callable $callback: Callback function.

Built-in Events: | Event Pattern | Description | | :--- | :--- | | key.{key}.hit | Fired when a key is successfully retrieved. | | key.{key}.miss | Fired when a key is not found or expired. | | key.{key}.delete | Fired when a key is manually deleted. | | system.flush.complete | Fired after a full flush operation. | | system.after | Fired during Manager destruction. |

Usage:

$cache->on('key.user.set', function ($key, $value) {
  error_log("Cache stored: {$key}");
});

$cache->on('key.user.miss', function ($key) {
  error_log("Cache miss for: {$key}");
});

fireEvent()

Manually trigger an event.

Parameters:

  • string $event: Event name.
  • mixed ...$args: Arguments to pass to listeners.

Usage:

$cache->fireEvent('custom:operation', 'user_1', $data);

Presets & Memoization

preset()

Retrieve a registered cache preset.

Parameters:

  • string $id: Preset identifier.

Returns: Cloned PendingCache instance.

Usage:

// Use stored preset
$user = $cache->preset('user_cache')->set($userData);

registerPreset()

Manually register a preset.

Parameters:

  • string $id: Preset identifier.
  • PendingCache $pending: PendingCache configuration.

Usage:

$template = $cache->key('user')
  ->ttl(3600)
  ->tags('users')
  ->namespace('app:users');

$cache->registerPreset('user_cache', $template);

updatePreset()

Update an existing preset.

Parameters:

  • string $id: Preset identifier.
  • callable $callback: Modification callback.

Usage:

$cache->updatePreset('user_cache', function ($pending) {
  $pending->ttl(7200); // Extend TTL to 2 hours
});

memo()

Create a memoized cache entry for complex operations.

Parameters:

  • string|null $driverName: Optional. Specific driver to use.

Returns: PendingCache for memoization.

Usage:

$result = $cache->memo('redis')
  ->ttl(300)
  ->set(expensiveCalculation());

cleanupMemo()

Clean up memoization registry.

Usage:

$cache->cleanupMemo(); // Usually called on shutdown

Driver Selection

Encryption Note: All storage drivers (except Blackhole) natively support AES-256-CBC encryption through the HasEncryption trait. Simply call ->encrypted() in your fluent chain.

Cachex provides five optimized drivers for different scenarios:

ArrayDriver

In-memory caching, perfect for testing and development. Configurable memory limits.

use Cachex\Drivers\ArrayDriver;

$driver = new ArrayDriver(maxMemory: 10240); // 10MB limit
$cache->addDriver('array', $driver);
$cache->driver('array');

$cache->set('key', 'value'); // Stored in RAM

Best for: Unit tests, development environments, temporary caching.

FilesDriver

File-based cache storage with filesystem organization. Supports encryption via HasEncryption trait.

use Cachex\Drivers\FilesDriver;

$driver = new FilesDriver('.cache/');
$cache->addDriver('files', $driver);

$cache->driver('files')->set('key', 'value', options: ['encrypted' => true]);

Best for: Production, persistent storage, shared hosting.

RedisDriver

High-performance Redis caching with multi-database support and encryption.

use Cachex\Drivers\RedisDriver;

$driver = new RedisDriver([
  'host'     => 'localhost',
  'port'     => 6379,
  'password' => null,
  'database' => 0,
]);
$cache->addDriver('redis', $driver);

$cache->driver('redis')->set('session', $sessionData, options: ['encrypted' => true]);

Best for: High-performance applications, distributed caching, session storage.

DatabaseDriver

SQL database-backed caching supporting PostgreSQL, MySQL, and MSSQL. Automatically creates schema.

use Cachex\Drivers\DatabaseDriver;

$pdo = new PDO('pgsql:host=localhost;dbname=app', 'user', 'password');

$driver = new DatabaseDriver([
  'connection'   => $pdo,
  'table_name'   => 'cachex_data',
  'table_prefix' => 'app_',
  'auto_create'  => true,
]);
$cache->addDriver('database', $driver);

$cache->driver('database')->set('report', $reportData);

Best for: Integrated database caching, complex queries, unified storage.

BlackholeDriver

No-op driver for disabling cache in tests or temporarily. All operations succeed but do nothing.

use Cachex\Drivers\BlackholeDriver;

$driver = new BlackholeDriver();
$cache->addDriver('blackhole', $driver);

$cache->driver('blackhole')->set('key', 'value'); // No effect
$cache->get('key'); // Always returns null

Best for: Testing, disabling cache in specific environments.

Core Concepts

Namespaces

Organize cache entries hierarchically:

// Set namespace
$cache->key('user_1')->namespace('users')->set($userData);

// Get with namespace
$user = $cache->key('user_1')->namespace('users')->get();

// Sub-namespaces
$cache->key('1')->namespace('users/active')->set($data);
$cache->key('1')->namespace('users/inactive')->set($data);

// Flush namespace
$cache->flush(['namespace' => 'users/active']); // Clears 'users/active'

Pro Tip: By default, the namespace() method is set to true, which uses the Manager's active namespace.

  • Pass false or null to switch to the Global Namespace.
  • Pass a string to use a specific custom namespace.

Tags & Tag-Based Flushing

Assign tags for batch operations:

// Tag entries
$cache->set('user_1', $user, tags: ['users', 'active', 'premium']);
$cache->set('user_2', $user, tags: ['users', 'inactive']);
$cache->set('post_1', $post, tags: ['posts', 'published']);

// Flush by tag
$cache->flushTags(['active']); // Clears user_1
$cache->flushTags(['users']); // Clears user_1 and user_2
$cache->flushTags(['posts', 'published']); // Clears post_1

TTL & Expiration

Control cache lifetime:

// 1 hour
$cache->set('session', $data, ttl: 3600);

// 1 day
$cache->key('daily')->ttl(86400)->set($data);

// No expiration
$cache->key('permanent')->ttl(0)->set($data);

Encryption

Secure sensitive data:

// Enable globally
$cache->config(['encryption_enabled' => true, 'encryption_key' => 'secret']);

// Per-entry
$cache->set('secret', $data, options: ['encrypted' => true]);

// Using fluent interface
$cache->key('password')->encrypted()->set($hashedPassword);

Version Control

Validate cache entries by version:

$cache->key('schema')->version('v2.0')->set($schemaData);

// Retrieve only if version matches
$schema = $cache->key('schema')->version('v2.0')->get(); // OK
$schema = $cache->key('schema')->version('v1.9')->get(); // Returns null (version mismatch)

Grace Periods

Extend cache validity beyond expiration:

// Set 5-minute grace period globally
$cache->config(['grace_period' => 300]);

// Per-operation
$data = $cache->key('data')->grace(600)->get(); // 10-minute grace

Driver Interface

All drivers implement DriverInterface with the following methods:

interface DriverInterface {
  public function get(
    string $key,
    mixed $default = null,
    ?string $namespace = null,
    ?int $grace = null,
    mixed $expectedVersion = null,
    array $options = []
  ): mixed;

  public function set(
    string $key,
    mixed $value,
    ?int $ttl = null,
    array $tags = [],
    ?string $version = null,
    bool $encryption = false,
    string|bool|null $namespace = true,
    array $options = []
  ): bool;

  public function delete(string $key, ?string $namespace = null, array $options = []): bool;
  public function flush(array $options = []): bool;
  public function has(string $key, ?string $namespace = null, ?int $grace = null, mixed $expectedVersion = null): bool;
  public function flushByTags(array $tags, array $options = []): bool;
  public function getMetadata(string $key): ?array;
}

Troubleshooting

  • "Driver not registered": Ensure you've called addDriver() before using it.
  • Redis connection failed: Verify Redis server is running at the configured host/port.
  • Encryption key is empty: Set encryption_key in config before using encryption.
  • File permissions denied: Ensure the cache directory is writable by the web server (755 or 777).
  • Cache not persisting: Check if caching is enabled via isEnabled() and the correct driver is selected.
  • Version mismatches: Ensure you're retrieving with the exact version used during set().
  • Tags not flushing: Verify tags were assigned during cache creation.
  • Memory limit exceeded: For ArrayDriver, increase maxMemory or flush entries regularly.

Contributing

Cachex is an open-source project and contributions are welcome! To contribute:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/your-feature)
  3. Commit your changes (git commit -am 'Add your feature')
  4. Push to the branch (git push origin feature/your-feature)
  5. Submit a Pull Request

Status

Cachex is currently under active development.

For updates on the development process, please refer to the CHANGELOG in dev branch.

License

This project is licensed under the Mozilla Public License 2.0 (MPL-2.0). You are free to use, modify, and distribute this library under the terms of the MPL-2.0. See the LICENSE file for details.

Made with ❤️ by Nael Dahman