tomloprod / memoize
Memoize is a lightweight PHP library designed to handle memoization with ease.
Fund package maintenance!
www.paypal.com/paypalme/tomloprod
Installs: 158
Dependents: 0
Suggesters: 0
Security: 0
Stars: 39
Watchers: 0
Forks: 2
Open Issues: 0
pkg:composer/tomloprod/memoize
Requires
- php: ^8.2.0
Requires (Dev)
- laravel/pint: ^1.22.1
- pestphp/pest: ^3.8.2
- pestphp/pest-plugin-type-coverage: ^3.5.0
- rector/rector: ^1.0.4
README
π§ Memoize
High-performance memoization library for PHP
π― About Memoize
Memoize is a lightweight PHP library designed to implement memoization and function caching techniques with ease.
Transform expensive function calls into lightning-fast cache lookups with zero configuration.
β¨ Features
π Key-based Memoization β‘ Single Execution π·οΈ Namespaces |
π§ LRU Cache π Cache Analytics π Runtime Flags |
π Quick Start
Installation
composer require tomloprod/memoize
Basic Usage
π·οΈ Namespace Organization
If you want to get the most out of the package and better organize your memoization, we recommend using namespaces.
When using namespaces, if you use a $key
with a null value, the callback wonβt be executed (especially useful in certain cases).
// Organize cache by context $userSettings = memoize() ->for(UserSettings::class) ->memo($userId, fn() => UserSettings::where('user_id', $userId)->first()); $productCache = memoize() ->for(Product::class) ->memo($productId, fn() => Product::with('variants')->find($productId));
π Key-based Memoization
You can also not use namespaces and just memoize keys.
// Expensive API call cached by key $weather = memoize()->memo( 'weather_london', fn() => Http::get('api.weather.com/london')->json() ); // Database query with dynamic key $user = memoize()->memo( "user_{$id}", fn() => User::with('profile', 'orders')->find($id) );
β‘ Single Execution Functions
// Initialize expensive resources only once $services = memoize()->once(fn() => [ 'redis' => new Redis(), 'elasticsearch' => new Client(), 'logger' => new Logger(), ]); $redis = $services()['redis']; // Initialized once $same = $services()['redis']; // Same instance
π§ Memory Management
The library uses an LRU (Least Recently Used) algorithm to automatically manage memory and prevent unlimited cache growth.
How does LRU work?
- Maintains a record of the access order for cache entries
- When the maximum limit (
maxSize
) is reached, automatically removes the least recently used entry - Every time you access an entry (read or write), it moves to the front of the queue
- Older entries remain at the end and are candidates for removal
This ensures that the most relevant and frequently used data remains in memory, while obsolete data is automatically removed.
// Set LRU cache limit (by default, there is no max size) memoize()->setMaxSize(1000); // Cache statistics $stats = memoize()->getStats(); // ['size' => 150, 'maxSize' => 1000, 'head' => [...], 'tail' => [...]] // Clear specific or all cache memoize()->forget('user_123'); memoize()->for('App\\Model\\User')->forget('123'); // Or clear all cache memoize()->flush();
π Runtime Flags
Control memoization behavior dynamically during execution with runtime flags. These flags exist only in memory and reset between requests/processes.
How do runtime flags work?
- Flags are stored in memory during the current execution
- They allow conditional behavior without external configuration
- Perfect for debug modes, logging control, and dynamic optimizations
- Automatically cleared when the process ends
// Skip cache during testing memoize()->enableFlag('bypass_cache'); $userData = memoize()->memo("user_{$id}", function() use ($id) { if (memoize()->hasFlag('bypass_cache')) { return User::fresh()->find($id); // Always fetch from DB in tests } return User::find($id); }); // Feature toggles without external dependencies memoize()->enableFlag('new_algorithm'); $result = memoize()->memo($cacheKey, function() { if (memoize()->hasFlag('new_algorithm')) { return $this->calculateWithNewAlgorithm(); } return $this->calculateWithOldAlgorithm(); }); // Development vs Production behavior if (app()->environment('local') && memoize()->hasFlag('dev_mode')) { memoize()->enableFlags(['verbose_logging', 'bypass_cache']); } // Model boot method with conditional service calls class Product extends Model { protected static function boot() { parent::boot(); static::updated(function ($product) { // Only call external stock service if flag is not set if (! memoize()->hasFlag('disableStockService')) { app(StockService::class)->updateInventory($product); } }); } }
Runtime Flag Methods:
Method | Description |
enableFlag(string $flag) | Enable a specific runtime flag |
disableFlag(string $flag) | Disable a specific runtime flag |
toggleFlag(string $flag) | Toggle flag state (enabled/disabled) |
hasFlag(string $flag): bool | Check if a specific flag is enabled |
enableFlags(array $flags) | Enable multiple flags at once |
disableFlags(array $flags) | Disable multiple flags at once |
hasAnyFlag(array $flags): bool | Check if at least one flag is enabled |
hasAllFlags(array $flags): bool | Check if all specified flags are enabled |
getFlags(): array | Get all currently enabled flags |
clearFlags() | Clear all enabled flags |
π‘ Advanced Examples
πββοΈ Performance Optimization
// Fibonacci with memoization - O(n) instead of O(2^n) function fibonacci(int $n): int { return memoize()->memo( "fib_{$n}", fn() => $n <= 1 ? $n : fibonacci($n - 1) + fibonacci($n - 2) ); } // Complex data aggregation $salesReport = memoize()->memo( "sales_report_{$month}", fn() => Order::whereMonth('created_at', $month) ->with('items.product') ->get() ->groupBy('status') ->map(fn($orders) => $orders->sum('total')) );
π API Reference
Core Methods
Method | Description |
memo(string|int|float|null $key, callable $callback) |
Key-based memoization - Execute callback and cache result by key. Returns cached value on subsequent calls. |
once(callable $callback) |
Single execution - Returns a wrapper function that executes the callback only once, caching the result forever. |
for(string $class) |
Namespace organization - Set namespace to organize cache by class/context. Automatically cleared after use. |
Cache Management
Method | Description |
has(string|int|float $key): bool | Check if a key exists in cache |
forget(string|int|float $key): bool | Remove specific key from cache |
flush(): void | Clear all cached values |
setMaxSize(?int $maxSize): void | Set maximum entries (LRU eviction) |
getStats(): array | Get detailed cache statistics |
βοΈ Requirements & Installation
- PHP 8.2+
- Composer
composer require tomloprod/memoize
π§βπ€βπ§ Contributing
Contributions are welcome, and are accepted via pull requests. Please review these guidelines before submitting any pull requests.
Memoize was created by TomΓ‘s LΓ³pez and open-sourced under the MIT license.