# Cache [hyperf/cache](https://github.com/hyperf/cache) 提供了基於 `Aspect` 實現的切面快取,也提供了實現 `Psr\SimpleCache\CacheInterface` 的快取類。 ## 安裝 ``` composer require hyperf/cache ``` ## 預設配置 | 配置 | 預設值 | 備註 | |:------:|:----------------------------------------:|:---------------------:| | driver | Hyperf\Cache\Driver\RedisDriver | 快取驅動,預設為 Redis | | packer | Hyperf\Utils\Packer\PhpSerializer | 打包器 | | prefix | c: | 快取字首 | ```php [ 'driver' => Hyperf\Cache\Driver\RedisDriver::class, 'packer' => Hyperf\Utils\Packer\PhpSerializerPacker::class, 'prefix' => 'c:', ], ]; ``` ## 使用 ### Simple Cache 方式 Simple Cache 也就是 [PSR-16](https://www.php-fig.org/psr/psr-16/) 規範,本元件適配了該規範,如果您希望使用實現 `Psr\SimpleCache\CacheInterface` 快取類,比如要重寫 `EasyWeChat` 的快取模組,可以直接從依賴注入容器中獲取 `Psr\SimpleCache\CacheInterface` 即可,如下所示: ```php $cache = $container->get(\Psr\SimpleCache\CacheInterface::class); ``` ### 註解方式 元件提供 `Hyperf\Cache\Annotation\Cacheable` 註解,作用於類方法,可以配置對應的快取字首、失效時間、監聽器和快取組。 例如,UserService 提供一個 user 方法,可以查詢對應 id 的使用者資訊。當加上 `Hyperf\Cache\Annotation\Cacheable` 註解後,會自動生成對應的 Redis 快取,key 值為 `user:id` ,超時時間為 `9000` 秒。首次查詢時,會從資料庫中查,後面查詢時,會從快取中查。 > 快取註解基於 [aop](zh-tw/aop.md) 和 [di](zh-tw/di.md),所以只有在 `Container` 中獲取到的物件例項才有效,比如通過 `$container->get` 和 `make` 方法所獲得的物件,直接 `new` 出來的物件無法使用。 ```php where('id',$id)->first(); if($user){ return $user->toArray(); } return null; } } ``` ### 清理 `@Cacheable` 生成的快取 當然,如果我們資料庫中的資料改變了,如何刪除快取呢?這裡就需要用到後面的監聽器。下面新建一個 Service 提供一方法,來幫我們處理快取。 ```php dispatcher->dispatch(new DeleteListenerEvent('user-update', [$userId])); return true; } } ``` 當我們自定義了 `Cacheable` 的 `value` 時,比如以下情況。 ```php dispatcher->dispatch(new DeleteListenerEvent('user-update', ['id' => $userId])); return true; } } ``` ## 註解介紹 ### Cacheable 例如以下配置,快取字首為 `user`, 超時時間為 `7200`, 刪除事件名為 `USER_CACHE`。生成對應快取 KEY 為 `c:user:1`。 ```php use App\Models\User; use Hyperf\Cache\Annotation\Cacheable; /** * @Cacheable(prefix="user", ttl=7200, listener="USER_CACHE") */ public function user(int $id): array { $user = User::query()->find($id); return [ 'user' => $user->toArray(), 'uuid' => $this->unique(), ]; } ``` 當設定 `value` 後,框架會根據設定的規則,進行快取 `KEY` 鍵命名。如下例項,當 `$user->id = 1` 時,快取 `KEY` 為 `c:userBook:_1` ```php use App\Models\User; use Hyperf\Cache\Annotation\Cacheable; /** * @Cacheable(prefix="userBook", ttl=6666, value="_#{user.id}") */ public function userBook(User $user): array { return [ 'book' => $user->book->toArray(), 'uuid' => $this->unique(), ]; } ``` ### CachePut `CachePut` 不同於 `Cacheable`,它每次呼叫都會執行函式體,然後再對快取進行重寫。所以當我們想更新快取時,可以呼叫相關方法。 ```php use App\Models\User; use Hyperf\Cache\Annotation\CachePut; /** * @CachePut(prefix="user", ttl=3601) */ public function updateUser(int $id) { $user = User::query()->find($id); $user->name = 'HyperfDoc'; $user->save(); return [ 'user' => $user->toArray(), 'uuid' => $this->unique(), ]; } ``` ### CacheEvict CacheEvict 更容易理解了,當執行方法體後,會主動清理快取。 ```php use Hyperf\Cache\Annotation\CacheEvict; /** * @CacheEvict(prefix="userBook", value="_#{id}") */ public function updateUserBook(int $id) { return true; } ``` ## 快取驅動 ### Redis 驅動 `Hyperf\Cache\Driver\RedisDriver` 會把快取資料存放到 `Redis` 中,需要使用者配置相應的 `Redis 配置`。此方式為預設方式。 ### 協程記憶體驅動 如果您需要將資料快取到 `Context` 中,可以嘗試此驅動。例如以下應用場景 `Demo::get` 會在多個地方呼叫多次,但是又不想每次都到 `Redis` 中進行查詢。 ```php getArray($userId)[$id] ?? 0; } /** * @Cacheable(prefix="test", group="co") */ public function getArray(int $userId): array { return $this->redis->hGetAll($userId); } } ``` 對應配置如下: ```php [ 'driver' => Hyperf\Cache\Driver\CoroutineMemoryDriver::class, 'packer' => Hyperf\Utils\Packer\PhpSerializerPacker::class, ], ]; ```