PHPackages                             iprodev/php-easycache - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. iprodev/php-easycache

ActiveLibrary[Database &amp; ORM](/categories/database)

iprodev/php-easycache
=====================

PHP EasyCache is a lightweight, multi-backend (APCu/Redis/File/PDO) with SWR caching library that speeds up repeated API calls with thread‑safe writes, per‑key TTLs, automatic cleanup, key sanitization, and optional compression.

v3.0.2(5mo ago)114623[3 PRs](https://github.com/iprodev/PHP-EasyCache/pulls)MITPHPPHP ^8.1CI passing

Since Jul 6Pushed 5mo ago2 watchersCompare

[ Source](https://github.com/iprodev/PHP-EasyCache)[ Packagist](https://packagist.org/packages/iprodev/php-easycache)[ GitHub Sponsors](https://github.com/iprodev)[ RSS](/packages/iprodev-php-easycache/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (8)Dependencies (5)Versions (12)Used By (0)

PHP EasyCache v3 — PSR‑16 Multi‑Backend Cache with SWR
======================================================

[](#php-easycache-v3--psr16-multibackend-cache-with-swr)

**EasyCache** is a pragmatic, batteries‑included cache library that implements the **PSR‑16 Simple Cache** interface and adds production‑grade features on top:

- 🚀 Multi‑tier storage: **APCu, Redis, File, and PDO (MySQL/PostgreSQL/SQLite)**
- 🔒 **Atomic writes** and **read locks** for file storage
- ⚡ **Full SWR** (*stale‑while‑revalidate* + *stale‑if‑error*), with non‑blocking per‑key locks
- 🔧 **Pluggable Serializer &amp; Compressor** (PHP/JSON + None/Gzip/Zstd)
- 🔄 Automatic **backfill** between tiers (e.g., a Redis hit is written back to APCu)
- 🎯 First‑class **Laravel** integration via a Service Provider &amp; Facade
- ✅ **Comprehensive test coverage** with PHPUnit
- 🛡️ **Improved error handling** with detailed logging support

> Version: **v3.0.1** — Requires **PHP 8.1+** and `psr/simple-cache:^3`.

📖 **Documentation in other languages:**

- [فارسی (Persian)](README_FA.md)
- [کوردی (Kurdish Sorani)](README_KU.md)

---

📦 Installation
--------------

[](#-installation)

```
composer require iprodev/php-easycache
```

### Optional dependencies

[](#optional-dependencies)

- `ext-apcu` for the APCu tier
- `ext-redis` or `predis/predis:^2.0` for the Redis tier
- `ext-zlib` for Gzip compression
- `ext-zstd` for Zstd compression

---

🚀 Quick Start (PSR‑16)
----------------------

[](#-quick-start-psr16)

```
use Iprodev\EasyCache\Cache\MultiTierCache;
use Iprodev\EasyCache\Storage\ApcuStorage;
use Iprodev\EasyCache\Storage\RedisStorage;
use Iprodev\EasyCache\Storage\FileStorage;
use Iprodev\EasyCache\Serialization\NativeSerializer;
use Iprodev\EasyCache\Compression\GzipCompressor;

// Tiers: APCu -> Redis -> File
$apcu  = new ApcuStorage('ec:');

// phpredis (example); predis is also supported
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redisStore = new RedisStorage($redis, 'ec:');

$file  = new FileStorage(__DIR__.'/cache');

$cache = new MultiTierCache(
    [$apcu, $redisStore, $file],
    new NativeSerializer(),
    new GzipCompressor(3),
    defaultTtl: 600
);

// PSR-16 API
$cache->set('user_42', ['id'=>42, 'name'=>'Ava'], 300);
$data = $cache->get('user_42'); // ['id'=>42, 'name'=>'Ava']
```

---

🎯 Core Features
---------------

[](#-core-features)

### 1. Multi-Tier Caching

[](#1-multi-tier-caching)

Organize your cache in tiers from fastest to slowest. The library automatically:

- Reads from the fastest available tier
- Writes to all tiers
- Backfills faster tiers when data is found in slower tiers

```
// Example: Memory -> Redis -> Database
$cache = new MultiTierCache(
    [
        new ApcuStorage('app:'),      // Fast: In-memory
        new RedisStorage($redis),     // Medium: Network cache
        new PdoStorage($pdo, 'cache') // Slow: Database fallback
    ],
    new NativeSerializer(),
    new NullCompressor(),
    3600 // 1 hour default TTL
);
```

### 2. Stale-While-Revalidate (SWR)

[](#2-stale-while-revalidate-swr)

When data expires but is still inside the SWR window, **stale data is served instantly** while a **refresh happens in the background**. This prevents cache stampedes and ensures fast response times.

```
$result = $cache->getOrSetSWR(
    key: 'posts_homepage',
    producer: function () {
        // Expensive API call or database query
        return fetchPostsFromDatabase();
    },
    ttl: 300,                  // 5 minutes of fresh data
    swrSeconds: 120,           // Serve stale up to 2 minutes after expiry
    staleIfErrorSeconds: 600,  // If refresh fails, serve stale up to 10 minutes
    options: ['mode' => 'defer'] // Defer refresh until after response
);
```

**How it works:**

1. If data is fresh, it's returned immediately
2. If data is expired but within SWR window:
    - Stale data is returned instantly
    - Background refresh is triggered (non-blocking)
3. If refresh fails, stale data continues to be served (within staleIfError window)

### 3. Pluggable Serialization

[](#3-pluggable-serialization)

Choose the serializer that fits your needs:

```
// PHP Native Serializer (supports objects)
use Iprodev\EasyCache\Serialization\NativeSerializer;
$cache = new MultiTierCache([$storage], new NativeSerializer());

// JSON Serializer (portable, faster for simple data)
use Iprodev\EasyCache\Serialization\JsonSerializer;
$cache = new MultiTierCache([$storage], new JsonSerializer());
```

### 4. Pluggable Compression

[](#4-pluggable-compression)

Save memory and disk space:

```
// No compression
use Iprodev\EasyCache\Compression\NullCompressor;
$cache = new MultiTierCache([$storage], $serializer, new NullCompressor());

// Gzip compression (balanced)
use Iprodev\EasyCache\Compression\GzipCompressor;
$cache = new MultiTierCache([$storage], $serializer, new GzipCompressor(5));

// Zstd compression (fastest)
use Iprodev\EasyCache\Compression\ZstdCompressor;
$cache = new MultiTierCache([$storage], $serializer, new ZstdCompressor(3));
```

---

💾 Storage Backends
------------------

[](#-storage-backends)

### APCu Storage

[](#apcu-storage)

Fast in-memory cache, perfect as the first tier.

```
use Iprodev\EasyCache\Storage\ApcuStorage;

$storage = new ApcuStorage(
    prefix: 'myapp:' // Namespace your keys
);
```

**Features:**

- Lightning-fast memory access
- Shared between PHP-FPM workers
- Automatic expiration
- Safe clear() that only deletes prefixed keys

### Redis Storage

[](#redis-storage)

Network-based cache with persistence options.

```
use Iprodev\EasyCache\Storage\RedisStorage;

// Using phpredis
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$storage = new RedisStorage($redis, 'myapp:');

// Using predis
$redis = new Predis\Client('tcp://127.0.0.1:6379');
$storage = new RedisStorage($redis, 'myapp:');
```

**Features:**

- Works with phpredis or predis
- TTL support with SETEX
- Safe clear() with prefix scanning
- Automatic expiration

### File Storage

[](#file-storage)

Reliable disk-based cache with sharding.

```
use Iprodev\EasyCache\Storage\FileStorage;

$storage = new FileStorage(
    path: '/var/cache/myapp',  // Cache directory
    ext: '.cache',              // File extension
    shards: 2                   // Directory sharding level (0-3)
);
```

**Features:**

- Atomic writes (temp file + rename)
- Read locks with flock()
- Directory sharding for performance
- Configurable file extension

**Directory Sharding Example:**

```
With shards=2, key "user_123" (hash: a1b2c3d4):
/var/cache/myapp/a1/b2/a1b2c3d4.cache

```

### PDO Storage

[](#pdo-storage)

SQL database cache for shared environments.

```
use Iprodev\EasyCache\Storage\PdoStorage;

$pdo = new PDO('mysql:host=localhost;dbname=cache', 'user', 'pass');
$storage = new PdoStorage($pdo, 'easycache');

// Create table (run once during setup)
$storage->ensureTable();
```

**Supported databases:**

- SQLite: `sqlite:/path/to/cache.db`
- MySQL: `mysql:host=localhost;dbname=cache`
- PostgreSQL: `pgsql:host=localhost;dbname=cache`

**Features:**

- TTL support with expiration check
- Prune expired items with `prune()`
- UPSERT support (INSERT ... ON CONFLICT)
- Indexed queries for performance

---

🎨 Complete Examples
-------------------

[](#-complete-examples)

### Example 1: Simple File Cache

[](#example-1-simple-file-cache)

```
use Iprodev\EasyCache\Cache\MultiTierCache;
use Iprodev\EasyCache\Storage\FileStorage;
use Iprodev\EasyCache\Serialization\NativeSerializer;
use Iprodev\EasyCache\Compression\NullCompressor;

$storage = new FileStorage(__DIR__ . '/cache');
$cache = new MultiTierCache([$storage], new NativeSerializer(), new NullCompressor());

// Set with 1 hour TTL
$cache->set('user_profile', [
    'id' => 123,
    'name' => 'John Doe',
    'email' => 'john@example.com'
], 3600);

// Get
$profile = $cache->get('user_profile');

// Check existence
if ($cache->has('user_profile')) {
    echo "Profile is cached!";
}

// Delete
$cache->delete('user_profile');
```

### Example 2: Multi-Tier with Backfill

[](#example-2-multi-tier-with-backfill)

```
// Setup: APCu (fast) -> Redis (medium) -> File (slow)
$apcu = new ApcuStorage('app:');
$redis = new RedisStorage($redisClient, 'app:');
$file = new FileStorage('/var/cache/app');

$cache = new MultiTierCache([$apcu, $redis, $file]);

// First request: Cache miss, data fetched and stored in all tiers
$data = $cache->get('expensive_data');

// APCu crashes and restarts...

// Next request: Data found in Redis, automatically backfilled to APCu
$data = $cache->get('expensive_data'); // Fast!
```

### Example 3: SWR for API Responses

[](#example-3-swr-for-api-responses)

```
use Psr\Log\LoggerInterface;

$cache = new MultiTierCache(
    [$apcu, $redis],
    new NativeSerializer(),
    new GzipCompressor(5),
    600, // 10 min default TTL
    $logger // Optional PSR-3 logger
);

$posts = $cache->getOrSetSWR(
    key: 'api_posts_latest',
    producer: function() use ($apiClient) {
        // This is expensive
        return $apiClient->fetchPosts();
    },
    ttl: 300,          // Fresh for 5 minutes
    swrSeconds: 60,    // Serve stale for 1 minute while refreshing
    staleIfErrorSeconds: 300, // Serve stale for 5 minutes if API fails
    options: ['mode' => 'defer'] // Refresh after response sent
);
```

### Example 4: Batch Operations

[](#example-4-batch-operations)

```
// Set multiple
$cache->setMultiple([
    'key1' => 'value1',
    'key2' => 'value2',
    'key3' => 'value3',
], 3600);

// Get multiple with default
$results = $cache->getMultiple(['key1', 'key2', 'missing'], 'default');
// ['key1' => 'value1', 'key2' => 'value2', 'missing' => 'default']

// Delete multiple
$cache->deleteMultiple(['key1', 'key2']);
```

### Example 5: DateInterval TTL

[](#example-5-dateinterval-ttl)

```
// Cache for 2 hours
$cache->set('key', 'value', new DateInterval('PT2H'));

// Cache for 1 day
$cache->set('key', 'value', new DateInterval('P1D'));

// Cache for 30 days
$cache->set('key', 'value', new DateInterval('P30D'));
```

### Example 6: Custom Logger Integration

[](#example-6-custom-logger-integration)

```
use Monolog\Logger;
use Monolog\Handler\StreamHandler;

$logger = new Logger('cache');
$logger->pushHandler(new StreamHandler('/var/log/cache.log', Logger::WARNING));

$cache = new MultiTierCache(
    [$storage],
    new NativeSerializer(),
    new NullCompressor(),
    3600,
    $logger // Will log warnings and errors
);
```

### Example 7: Scheduled Cleanup

[](#example-7-scheduled-cleanup)

```
// Run this in a cron job or scheduled task
$pruned = $cache->prune();
echo "Pruned {$pruned} expired items";

// For PDO storage, this removes expired rows
// For File/APCu/Redis, expiration is automatic
```

---

🎭 Laravel Integration
---------------------

[](#-laravel-integration)

### Setup

[](#setup)

1. **Install the package:**

```
composer require iprodev/php-easycache
```

2. **Publish configuration:**

```
php artisan vendor:publish --tag=easycache-config
```

3. **Configure in `config/easycache.php`:**

```
return [
    'drivers' => ['apcu', 'redis', 'file'],
    'default_ttl' => 600,

    'serializer' => [
        'driver' => 'php', // php|json
    ],

    'compressor' => [
        'driver' => 'gzip', // none|gzip|zstd
        'level' => 5,
    ],

    'redis' => [
        'host' => env('REDIS_HOST', '127.0.0.1'),
        'port' => env('REDIS_PORT', 6379),
        'password' => env('REDIS_PASSWORD', null),
        'database' => env('REDIS_CACHE_DB', 1),
    ],
];
```

### Using the Facade

[](#using-the-facade)

```
use EasyCache;

// Simple operations
EasyCache::set('user_settings', $settings, 3600);
$settings = EasyCache::get('user_settings');

// SWR pattern
$data = EasyCache::getOrSetSWR(
    'dashboard_stats',
    fn() => $this->computeStats(),
    300,  // Fresh for 5 min
    60,   // SWR for 1 min
    300   // Stale-if-error for 5 min
);

// Batch operations
EasyCache::setMultiple([
    'key1' => 'value1',
    'key2' => 'value2',
]);
```

### Artisan Commands

[](#artisan-commands)

The package includes a prune command:

```
# Prune expired cache items
php artisan easycache:prune

# Add to your scheduler (app/Console/Kernel.php)
$schedule->command('easycache:prune')->daily();
```

---

🔑 Key Rules (PSR‑16)
--------------------

[](#-key-rules-psr16)

- **Allowed characters:** `[A-Za-z0-9_.]`
- **Max length:** 64 characters
- **Reserved characters (not allowed):** `{ } ( ) / \ @ :`

```
// Valid keys
$cache->set('user_123', $data);
$cache->set('posts.latest', $data);
$cache->set('CamelCase', $data);

// Invalid keys (will throw InvalidArgument exception)
$cache->set('user:123', $data);    // Contains :
$cache->set('user/123', $data);    // Contains /
$cache->set('user@123', $data);    // Contains @
$cache->set(str_repeat('x', 65), $data); // Too long
```

---

🧪 Testing &amp; Quality Assurance
---------------------------------

[](#-testing--quality-assurance)

### Running Tests

[](#running-tests)

```
# Run all tests
composer test

# Run with coverage
composer test -- --coverage-html coverage

# Run specific test suite
./vendor/bin/phpunit --testsuite "Storage Tests"
```

### Static Analysis

[](#static-analysis)

```
# Run PHPStan
composer stan

# Check coding standards
composer cs

# Fix coding standards automatically
composer cs:fix
```

### Test Coverage

[](#test-coverage)

The library includes comprehensive tests for:

- ✅ All storage backends (File, APCu, Redis, PDO)
- ✅ Multi-tier caching with backfill
- ✅ SWR functionality
- ✅ Serializers (Native, JSON)
- ✅ Compressors (Null, Gzip, Zstd)
- ✅ Key validation
- ✅ Lock mechanism
- ✅ Edge cases and error handling

---

🔧 Advanced Configuration
------------------------

[](#-advanced-configuration)

### Custom Lock Path

[](#custom-lock-path)

```
$cache = new MultiTierCache(
    [$storage],
    $serializer,
    $compressor,
    3600,
    $logger,
    '/custom/lock/path' // Custom lock directory
);
```

### File Storage Sharding Levels

[](#file-storage-sharding-levels)

```
// No sharding: /cache/md5hash.cache
$storage = new FileStorage('/cache', '.cache', 0);

// 1 level: /cache/a1/md5hash.cache
$storage = new FileStorage('/cache', '.cache', 1);

// 2 levels: /cache/a1/b2/md5hash.cache (recommended)
$storage = new FileStorage('/cache', '.cache', 2);

// 3 levels: /cache/a1/b2/c3/md5hash.cache
$storage = new FileStorage('/cache', '.cache', 3);
```

### Environment Variables (Laravel)

[](#environment-variables-laravel)

```
# .env file
EASYCACHE_DRIVER=redis
EASYCACHE_REDIS_HOST=127.0.0.1
EASYCACHE_REDIS_PORT=6379
EASYCACHE_REDIS_PASSWORD=secret
EASYCACHE_REDIS_DB=1
EASYCACHE_DEFAULT_TTL=600
```

---

🚨 Error Handling
----------------

[](#-error-handling)

All storage operations are wrapped with proper error handling. Failures are logged (if logger is provided) and don't crash your application:

```
use Monolog\Logger;

$logger = new Logger('cache');
$cache = new MultiTierCache([$storage], $serializer, $compressor, 3600, $logger);

// If storage fails, operation returns false but doesn't throw
$result = $cache->set('key', 'value');
if (!$result) {
    // Check logs for details
    echo "Cache set failed, check logs";
}
```

**Logged Events:**

- Storage read/write failures
- Compression/decompression errors
- Lock acquisition failures
- SWR refresh errors
- Serialization errors

---

🔄 Backwards Compatibility
-------------------------

[](#-backwards-compatibility)

For projects upgrading from v2, use the BC wrapper:

```
use Iprodev\EasyCache\EasyCache;

$cache = new EasyCache([
    'cache_path' => __DIR__ . '/cache',
    'cache_extension' => '.cache',
    'cache_time' => 3600,
    'directory_shards' => 2,
]);

// Works like v2
$cache->set('key', 'value');
$value = $cache->get('key');
```

---

📝 Best Practices
----------------

[](#-best-practices)

1. **Use multi-tier wisely:** APCu → Redis → File/PDO
2. **Set appropriate TTLs:** Balance freshness vs. performance
3. **Use SWR for expensive operations:** Prevent cache stampedes
4. **Monitor cache hit rates:** Use logging to track performance
5. **Schedule pruning:** For PDO storage, prune regularly
6. **Use compression for large data:** GzipCompressor or ZstdCompressor
7. **Namespace your keys:** Use prefixes to avoid collisions
8. **Test error scenarios:** Ensure your app handles cache failures gracefully

---

🤝 Contributing
--------------

[](#-contributing)

Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details.

### Development Setup

[](#development-setup)

```
git clone https://github.com/iprodev/php-easycache.git
cd php-easycache
composer install
composer test
```

---

📄 License
---------

[](#-license)

MIT © iprodev

---

🔗 Links
-------

[](#-links)

- [Documentation](https://github.com/iprodev/php-easycache/wiki)
- [API Reference - English](API.md)
- [API Reference - فارسی](API_FA.md)
- [API Reference - کوردی](API_KU.md)
- [Examples - English](EXAMPLES.md)
- [Examples - فارسی](EXAMPLES_FA.md)
- [Examples - کوردی](EXAMPLES_KU.md)
- [Changelog](CHANGELOG.md)
- [Security Policy](SECURITY.md)
- [Code of Conduct](CODE_OF_CONDUCT.md)

---

💬 Support
---------

[](#-support)

- 📧 Email:
- 🐛 Issues: [GitHub Issues](https://github.com/iprodev/php-easycache/issues)
- 💡 Discussions: [GitHub Discussions](https://github.com/iprodev/php-easycache/discussions)

###  Health Score

49

—

FairBetter than 95% of packages

Maintenance70

Regular maintenance activity

Popularity21

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity78

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~542 days

Recently: every ~894 days

Total

8

Last Release

169d ago

Major Versions

1.2.1 → v2.0.02025-10-08

v2.0.0 → v3.0.02025-10-09

PHP version history (2 changes)1.0.0PHP &gt;=5.3.0

v3.0.0PHP ^8.1

### Community

Maintainers

![](https://www.gravatar.com/avatar/937da402a50db921c9d22766072f9d497bfd27e5b397fd63005a0db84c9f6b87?d=identicon)[iprodev](/maintainers/iprodev)

---

Top Contributors

[![iprodev](https://avatars.githubusercontent.com/u/1952944?v=4)](https://github.com/iprodev "iprodev (20 commits)")

---

Tags

laravelcompressionmysqlsqlitepostgresqlredisserializationcachepsr-16apcufile cacheswrstale-while-revalidatemulti-tier

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/iprodev-php-easycache/health.svg)

```
[![Health](https://phpackages.com/badges/iprodev-php-easycache/health.svg)](https://phpackages.com/packages/iprodev-php-easycache)
```

###  Alternatives

[doctrine/dbal

Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.

9.7k578.4M5.6k](/packages/doctrine-dbal)[matthiasmullie/scrapbook

Scrapbook is a PHP cache library, with adapters for e.g. Memcached, Redis, Couchbase, APCu, SQL and additional capabilities (e.g. transactions, stampede protection) built on top.

3212.5M32](/packages/matthiasmullie-scrapbook)[desarrolla2/cache

Provides an cache interface for several adapters Apc, Apcu, File, Mongo, Memcache, Memcached, Mysql, Mongo, Redis is supported.

1322.5M47](/packages/desarrolla2-cache)[apix/cache

A thin PSR-6 cache wrapper with a generic interface to various caching backends emphasising cache taggging and indexing to Redis, Memcached, PDO/SQL, APC and other adapters.

114542.8k6](/packages/apix-cache)[tommyknocker/pdo-database-class

Framework-agnostic PHP database library with unified API for MySQL, MariaDB, PostgreSQL, SQLite, MSSQL, and Oracle. Query Builder, caching, sharding, window functions, CTEs, JSON, migrations, ActiveRecord, CLI tools, AI-powered analysis. Zero external dependencies.

845.7k](/packages/tommyknocker-pdo-database-class)[vcian/laravel-db-auditor

Database DB Auditor provide leverage to audit your MySql,sqlite, PostgreSQL database standards and also provide options to add constraints in table.

28535.1k1](/packages/vcian-laravel-db-auditor)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
