jarir-ahmed/cache 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

jarir-ahmed/cache

最新稳定版本:v1.1.0

Composer 安装命令:

composer require jarir-ahmed/cache

包简介

Framework-agnostic caching toolkit for PHP: PSR-16 + PSR-6, Redis/Memcached/APCu/File/PDO/tiered stores, tags, atomic locks, stampede protection, and HTTP caching (ETag/304, full-page).

README 文档

README

A framework-agnostic caching toolkit for PHP — every common cache type behind one clean API: in-memory, file, APCu, Redis, Memcached, PDO (database), and tiered (multi-layer). Plus PSR-16 + PSR-6 for drop-in use in any framework, tags, atomic locks, stampede protection, and HTTP caching (ETag/304, full-page, PSR-15 middleware).

PHP PSR-16 PSR-6 License

Zero required dependencies beyond the PSR cache interfaces. Redis and Memcached work with no PHP extension (built-in raw-socket clients) and automatically use ext-redis / ext-memcached when present.

Install

composer require jarir-ahmed/cache

Why

"Framework-level caching for any framework" = implement the standards. This package is a PSR-16 and PSR-6 implementation, so it drops straight into Laravel, Symfony, Slim, Mezzio, Doctrine, or raw PHP — while also giving you a richer native API and an HTTP caching layer most libraries skip.

Quick start

use JarirAhmed\Cache\Cache;
use JarirAhmed\Cache\Store\ArrayStore;

$cache = Cache::repository(new ArrayStore);

$cache->set('key', 'value', 60);                       // ttl seconds (null = forever)
$cache->get('key', 'default');
$cache->remember('user:1', 300, fn () => loadUser(1)); // compute once, then cache
$cache->increment('hits');
$cache->tags(['users'])->flush();

Config-driven, named stores

$cache = Cache::create([
    'default'    => 'redis',
    'prefix'     => 'app:',
    'serializer' => 'php',            // php | json | igbinary
    'stores' => [
        'redis'     => ['driver' => 'redis', 'host' => '127.0.0.1', 'port' => 6379],
        'memcached' => ['driver' => 'memcached', 'host' => '127.0.0.1', 'port' => 11211],
        'files'     => ['driver' => 'file', 'path' => '/var/cache/app'],
        'db'        => ['driver' => 'pdo', 'pdo' => $pdo, 'table' => 'cache'],
        'fast'      => ['driver' => 'tiered', 'layers' => ['array', 'redis']],
    ],
]);

$cache->store('redis')->set('k', $value, 3600);
$cache->store('fast')->remember('hot', 60, fn () => compute());

Stores

Driver Class Notes
array ArrayStore per-request memory
file FileStore sharded dirs, atomic writes
apcu ApcuStore shared memory (ext-apcu)
redis RedisStore raw-socket RESP or ext-redis
memcached MemcachedStore raw-socket text proto or ext-memcached
pdo PdoStore sqlite/mysql/pgsql, self-creating table
null NullStore disables caching
tiered TieredStore L1+L2, read-through back-fill

Redis without any extension:

use JarirAhmed\Cache\Store\RedisStore;

$redis = Cache::repository(RedisStore::connect('127.0.0.1', 6379)); // uses ext-redis if loaded, else raw socket

PSR-16 and PSR-6 (use it in any framework)

$psr16 = Cache::psr16(new RedisStore(...));   // Psr\SimpleCache\CacheInterface
$psr16->set('k', 'v', 3600);

$pool  = Cache::psr6(new FileStore('/tmp'));   // Psr\Cache\CacheItemPoolInterface
$item  = $pool->getItem('k');
if (! $item->isHit()) { $item->set(compute())->expiresAfter(600); $pool->save($item); }
  • Symfony: pass the PSR-6 pool anywhere a CacheItemPoolInterface is expected.
  • Doctrine: same — it consumes PSR-6.
  • Laravel: use Bridge\LaravelStore to register a custom driver (Cache::extend(...)).

Tags

$cache->tags(['users', 'profiles'])->put('u:1', $data, 3600);
$cache->tags(['users'])->flush();              // invalidate every 'users' entry at once

Atomic locks & stampede protection

// distributed lock
$cache->lock('import', 30)->get(function () {
    runImportOnce();                           // only one process at a time
});

// single-flight: under load, ONE caller computes, the rest wait for the result
$report = $cache->rememberLocked('daily-report', 600, fn () => buildExpensiveReport());

HTTP caching

use JarirAhmed\Cache\Http\HttpCache;
use JarirAhmed\Cache\Http\CacheControl;

echo HttpCache::serve($body, [
    'etag'          => true,
    'cache_control' => CacheControl::make()->public()->maxAge(300)->staleWhileRevalidate(60),
]);   // emits ETag + Cache-Control, replies 304 automatically on If-None-Match

Full-page cache:

use JarirAhmed\Cache\Http\PageCache;

$page = new PageCache($cache->store(), ttl: 120);

if (($html = $page->start('home')) !== null) { echo $html; return; } // cache hit
// ... render your page ...
echo $page->end('home');                                             // capture + store

PSR-15 middleware (Slim/Mezzio/Laminas):

use JarirAhmed\Cache\Http\CacheMiddleware;

$app->add(new CacheMiddleware($cache->store(), $psr17ResponseFactory, ttl: 60));

Serializers

php (default, any value), json (portable, scalars/arrays), igbinary (compact binary, needs ext-igbinary). Set per store via the serializer config key or pass a Serializer instance.

Architecture

Store (contract) ─ Array | File | Apcu | Redis | Memcached | Pdo | Null | Tiered
Repository ─ rich API (remember/add/pull/increment/tags/lock/rememberLocked) over a Store
Psr16Cache / Psr6Pool ─ standards adapters
Lock + StoreLock ─ atomic mutex (single-flight)
Tags: TagSet + TaggedCache ─ group invalidation
Http: CacheControl, HttpCache (ETag/304), PageCache, CacheMiddleware (PSR-15)
Cache / CacheManager ─ factory + named stores

Testing

composer test

The suite runs one shared contract against every store. Redis/Memcached tests run when those servers are reachable and skip otherwise; raw-socket and extension paths are both covered.

License

MIT.

统计信息

  • 总下载量: 1
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 3
  • 依赖项目数: 1
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-06-10

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固