Scrapbook

キャッシュライブラリPHPPSR-6PSR-16マルチアダプター

GitHub概要

matthiasmullie/scrapbook

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

スター317
ウォッチ9
フォーク27
作成日:2015年9月3日
言語:PHP
ライセンス:MIT License

トピックス

apccachecachingmemcachedphppsr-16psr-6redistransactions

スター履歴

matthiasmullie/scrapbook Star History
データ取得日時: 2025/10/22 08:07

キャッシュライブラリ

Scrapbook

概要

ScrapbookはPHP用のキャッシュライブラリで、Memcached、Redis、Couchbase、APC(u)、SQLなどの複数のアダプターをサポートし、PSR-6およびPSR-16準拠のキャッシュ機能を提供します。

詳細

Scrapbookは、様々なキャッシュバックエンドに対する統一されたインターフェースを提供するPHPキャッシュライブラリです。レイヤー構造で設計されており、すべてKeyValueStore実装として相互にラップできます。トランザクション、スタンピード保護、バッファリングなどの高度な機能を内蔵し、堅牢性と開発の容易性、スケーラビリティを向上させます。PSR-6(Cache)とPSR-16(SimpleCache)の両方の標準に準拠しており、既存のPHPアプリケーションとの統合が簡単です。Memcached、Redis、SQLite、MySQL、APC、Couchbaseなど幅広いストレージバックエンドをサポートしています。

メリット・デメリット

メリット

  • マルチアダプター: Memcached、Redis、SQL、APC など豊富なバックエンド
  • PSR準拠: PSR-6およびPSR-16標準に完全準拠
  • 高度な機能: トランザクション、スタンピード保護、バッファリング
  • レイヤー構造: 機能を組み合わせて柔軟なキャッシュシステムを構築
  • 型安全: しっかりとした型チェックとエラーハンドリング
  • Composer対応: 簡単なインストールと依存関係管理

デメリット

  • PHP専用: 他の言語では使用できない
  • 学習コスト: 高度な機能を使うには理解が必要
  • バックエンド依存: 選択したストレージの制約を受ける
  • 設定複雑性: 複数レイヤーの組み合わせは設定が複雑

主要リンク

書き方の例

基本的な使用方法

<?php
use MatthiasMullie\Scrapbook\Adapters\MemoryStore;
use MatthiasMullie\Scrapbook\Adapters\Memcached;

// メモリストア(開発・テスト用)
$cache = new MemoryStore();

// Memcached の使用
$memcached = new \Memcached();
$memcached->addServer('localhost', 11211);
$cache = new Memcached($memcached);

// 基本操作
$cache->set('key', 'value');
$value = $cache->get('key'); // returns 'value'
$success = $cache->delete('key');

SQLite での使用

<?php
use MatthiasMullie\Scrapbook\Adapters\SQLite;

// SQLite データベース接続
$pdo = new PDO('sqlite:cache.db');
$cache = new SQLite($pdo);

// 基本的なキャッシュ操作
$cache->set('user:123', ['name' => 'John', 'email' => '[email protected]']);
$user = $cache->get('user:123');

// TTL付きでの保存
$cache->set('session:abc', $sessionData, time() + 3600); // 1時間後に期限切れ

Redis での使用

<?php
use MatthiasMullie\Scrapbook\Adapters\Redis;

// Redis接続
$redis = new \Redis();
$redis->connect('127.0.0.1', 6379);
$cache = new Redis($redis);

// 複数の値を一度に設定
$cache->setMultiple([
    'product:1' => ['name' => 'Laptop', 'price' => 999],
    'product:2' => ['name' => 'Mouse', 'price' => 25],
]);

// 複数の値を一度に取得
$products = $cache->getMultiple(['product:1', 'product:2']);

PSR-6 Cache の使用

<?php
use MatthiasMullie\Scrapbook\Psr6\Pool;
use MatthiasMullie\Scrapbook\Adapters\Redis;

// キャッシュプールの作成
$redis = new \Redis();
$redis->connect('127.0.0.1', 6379);
$cache = new Redis($redis);
$pool = new Pool($cache);

// PSR-6 インターフェースでの操作
$item = $pool->getItem('expensive_operation');

if (!$item->isHit()) {
    $result = performExpensiveOperation();
    $item->set($result);
    $item->expiresAfter(3600); // 1時間後に期限切れ
    $pool->save($item);
}

$data = $item->get();

PSR-16 SimpleCache の使用

<?php
use MatthiasMullie\Scrapbook\Psr16\SimpleCache;
use MatthiasMullie\Scrapbook\Adapters\Memcached;

// SimpleCache の作成
$memcached = new \Memcached();
$memcached->addServer('localhost', 11211);
$cache = new Memcached($memcached);
$simpleCache = new SimpleCache($cache);

// シンプルなキャッシュ操作
$value = $simpleCache->get('key', 'default_value');
$simpleCache->set('key', 'new_value', 300); // 5分間キャッシュ

// 複数操作
$values = $simpleCache->getMultiple(['key1', 'key2'], 'default');
$simpleCache->setMultiple(['key1' => 'value1', 'key2' => 'value2'], 600);

バッファリング機能

<?php
use MatthiasMullie\Scrapbook\Buffered\BufferedStore;
use MatthiasMullie\Scrapbook\Adapters\Redis;

// Redis + バッファリング
$redis = new \Redis();
$redis->connect('127.0.0.1', 6379);
$cache = new Redis($redis);
$buffered = new BufferedStore($cache);

// バッファされた操作
$buffered->set('key1', 'value1');
$buffered->set('key2', 'value2');
$buffered->delete('key3');

// すべての操作を一度に実行
$buffered->commit();

トランザクション機能

<?php
use MatthiasMullie\Scrapbook\Adapters\MemoryStore;

$cache = new MemoryStore();

// トランザクション開始
$transaction = $cache->getCollection('transaction');

try {
    $transaction->set('user:123', $userData);
    $transaction->set('session:abc', $sessionData);
    
    // すべて成功した場合のみコミット
    $success = $transaction->commit();
    
    if (!$success) {
        throw new Exception('Transaction failed');
    }
} catch (Exception $e) {
    // エラー時はロールバック
    $transaction->rollback();
    throw $e;
}

スタンピード保護

<?php
use MatthiasMullie\Scrapbook\Adapters\Redis;

class ExpensiveDataService {
    private $cache;
    
    public function __construct() {
        $redis = new \Redis();
        $redis->connect('127.0.0.1', 6379);
        $this->cache = new Redis($redis);
    }
    
    public function getExpensiveData($key) {
        // キャッシュから取得を試行
        $data = $this->cache->get($key);
        
        if ($data === false) {
            // ロックを取得してスタンピードを防ぐ
            $lock = $this->cache->get($key . ':lock');
            
            if ($lock === false) {
                // ロックを設定(短い期間)
                $this->cache->set($key . ':lock', true, 30);
                
                try {
                    // 重い処理を実行
                    $data = $this->performExpensiveOperation();
                    
                    // 結果をキャッシュ(長い期間)
                    $this->cache->set($key, $data, 3600);
                } finally {
                    // ロックを解除
                    $this->cache->delete($key . ':lock');
                }
            } else {
                // 他のプロセスが処理中の場合は少し待つ
                sleep(1);
                return $this->getExpensiveData($key);
            }
        }
        
        return $data;
    }
}