# Cache [hyperf/cache](https://github.com/hyperf-cloud/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\PhpSerializer::class, 'prefix' => 'c:', ], ]; ``` ## 使用 ### SimpleCache 方式 如果您只想使用实现 `Psr\SimpleCache\CacheInterface` 缓存类,比如重写 `EasyWeChat` 缓存模块,可以很方便的从 `Container` 中获取相应对象。 ```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/aop.md) 和 [di](zh/di.md),所以只有在 `Container` 中获取到的对象实例才有效,比如通过 `$container->get` 和 `make` 方法所获得的对象,直接 `new` 出来的对象无法使用。 ```php where('id',$id)->first(); if($user){ return $user->toArray(); } return null; } } ``` ### 清理注解缓存 当然,如果我们数据库中的数据改变了,如何删除缓存呢?这里就需要用到后面的监听器。下面新建一个 Service 提供一方法,来帮我们处理缓存。 ```php dispatcher->dispatch(new DeleteListenerEvent('user-update', [$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配置`。此方式为默认方式。 ### 协程内存驱动 > 本驱动乃Beta版本,请谨慎使用。 如果您需要将数据缓存到 `Context` 中,可以尝试此驱动。例如以下应用场景 `Demo::get` 会在多个地方调用多次,但是又不想每次都到 `Redis` 中进行查询。 ```php getArray($userId)[$id] ?? 0; } /** * @Cacheable(prefix="test", group="co") * @param int $userId * @return array */ public function getArray($userId) { return $this->redis->hGetAll($userId); } } ``` 对应配置如下: ```php [ 'driver' => Hyperf\Cache\Driver\CoroutineMemoryDriver::class, 'packer' => Hyperf\Utils\Packer\PhpSerializerPacker::class, ], ]; ```