前言
Laravel 支持多种缓存系统, 并提供了统一的api接口.
(Laravel 5.5)默认支持的存储驱动包括如下:
- file (默认使用)
- apc
- array (数组, 测试用)
- database (关系型数据库)
- memcached
- redis
默认的缓存配置文件在 config/cache.php
参考链接:
使用
直接使用Laravel为我们提供的Facade
use IlluminateSupportFacadesCache;
$cache = Cache::get('key');
支持的大部分方法:
Cache::put('key', 'value', $minutes);
Cache::add('key', 'value', $minutes);
Cache::forever('key', 'value');
Cache::remember('key', $minutes, function(){ return 'value' });
Cache::rememberForever('key', function(){ return 'value' });
Cache::forget('key');
Cache::has('key');
Cache::get('key');
Cache::get('key', 'default');
Cache::get('key', function(){ return 'default'; });
Cache::tags('my-tag')->put('key','value', $minutes);
Cache::tags('my-tag')->has('key');
Cache::tags('my-tag')->get('key');
Cache::tags('my-tag')->forget('key');
Cache::tags('my-tag')->flush();
Cache::increment('key');
Cache::increment('key', $amount);
Cache::decrement('key');
Cache::decrement('key', $amount);
Cache::tags('group')->put('key', $value);
Cache::tags('group')->get('key');
Cache::tags('group')->flush();
其他使用方法请参照官方翻译(中文)文档: https://learnku.com/docs/laravel/5.5/cache/1316
源码
Laravel 中常用 Cache Facade 来操作缓存, 对应的实际类是 IlluminateCacheCacheManager
缓存管理类(工厂).
Cache::xxx()
我们通过 CacheManager
类获取持有不同存储驱动的 IlluminateCacheRepository
类
CacheManager::store($name = null)
Repository
仓库类代理了实现存储驱动接口 IlluminateContractsCacheStore
的类实例.
Cache Facade
首先从 Cache Facade 开始分析, 先看一下其源码:
<?php
namespace IlluminateSupportFacades;
/**
* @see IlluminateCacheCacheManager
* @see IlluminateCacheRepository
*/
class Cache extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'cache';
}
}
在配置文件 configapp.php
中定义了 Cache 服务提供者
//...
'providers' => [
// ......
IlluminateCacheCacheServiceProvider::class,
// ......
],
//...
IlluminateCacheCacheServiceProvider
源文件:
<?php
namespace IlluminateCache;
use IlluminateSupportServiceProvider;
class CacheServiceProvider extends ServiceProvider
{
// ......
public function register()
{
$this->app->singleton('cache', function ($app) {
return new CacheManager($app);
});
$this->app->singleton('cache.store', function ($app) {
return $app['cache']->driver();
});
$this->app->singleton('memcached.connector', function () {
return new MemcachedConnector;
});
}
// ......
}
通过上面源码可知, Cache Facade 关联的项是 IlluminateCacheCacheManager
, 也就是我们通过 Cache Facade 实际调用的是 CacheManager
实例的方法.
CacheManager
<?php
namespace IlluminateContractsCache;
interface Factory
{
/**
* Get a cache store instance by name.
*
* @param string|null $name
* @return IlluminateContractsCacheRepository
*/
public function store($name = null);
}
CacheManager 实现了 IlluminateContractsCacheFactory
接口(↑), 即实现了一个简单工厂, 传入存储驱动名, 返回对应的驱动实例.
CacheManager实现的简单工厂接口方法:
<?php
namespace IlluminateCache;
use Closure;
use InvalidArgumentException;
use IlluminateContractsCacheStore;
use IlluminateContractsCacheFactory as FactoryContract;
use IlluminateContractsEventsDispatcher as DispatcherContract;
/**
* @mixin IlluminateContractsCacheRepository
*/
class CacheManager implements FactoryContract
{
/**
* Get a cache store instance by name.
*
* @param string|null $name
* @return IlluminateContractsCacheRepository
*/
public function store($name = null)
{
$name = $name ?: $this->getDefaultDriver();
return $this->stores[$name] = $this->get($name);
}
/**
* Get the default cache driver name.
*
* @return string
*/
public function getDefaultDriver()
{
return $this->app['config']['cache.default'];
}
/**
* Attempt to get the store from the local cache.
*
* @param string $name
* @return IlluminateContractsCacheRepository
*/
protected function get($name)
{
return $this->stores[$name] ?? $this->resolve($name);
}
/**
* Resolve the given store.
*
* @param string $name
* @return IlluminateContractsCacheRepository
*
* @throws InvalidArgumentException
*/
protected function resolve($name)
{
$config = $this->getConfig($name);
if (is_null($config)) {
throw new InvalidArgumentException("Cache store [{$name}] is not defined.");
}
if (isset($this->customCreators[$config['driver']])) {
return $this->callCustomCreator($config);
} else {
$driverMethod = 'create'.ucfirst($config['driver']).'Driver';
if (method_exists($this, $driverMethod)) {
return $this->{$driverMethod}($config);
} else {
throw new InvalidArgumentException("Driver [{$config['driver']}] is not supported.");
}
}
}
/**
* Dynamically call the default driver instance.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
return $this->store()->$method(...$parameters);
}
}
可以看到 CacheManager
提供了会话级别的实例缓存, 当解析驱动名时, 它会按如下顺序解析:
- 自定义驱动: 查看是否有通过
CacheManager::extend(...)
自定义的驱动 - Laravel提供的驱动: 查看是否存在
CacheManager::createXxxDriver(...)
方法
这些方法返回的实例必须是实现了 IlluminateContractsCacheRepository
接口
本质上, CacheManager
就是一个提供了会话级别缓存的 Repository
实例工厂, 同时它提供了一个 __call
魔术方法, 以便快速调用默认缓存驱动.
$value = Cache::store('file')->get('foo');
// 通过 _call, 调用默认缓存驱动的 get 方法
$value = Cache::get('key');
Repository
IlluminateContractsCacheRepository
接口
<?php
namespace IlluminateContractsCache;
use Closure;
use PsrSimpleCacheCacheInterface;
interface Repository extends CacheInterface
{
public function has($key);
public function get($key, $default = null);
public function pull($key, $default = null);
public function put($key, $value, $minutes);
public function add($key, $value, $minutes);
public function increment($key, $value = 1);
public function decrement($key, $value = 1);
public function forever($key, $value);
public function remember($key, $minutes, Closure $callback);
public function sear($key, Closure $callback);
public function rememberForever($key, Closure $callback);
public function forget($key);
public function getStore();
}
Repository 是一个符合 PSR-16: Common Interface for Caching Libraries 规范的缓存仓库类, 其在Laravel相应的实现类: IlluminateCacheRepository
IlluminateCacheRepository
部分代码如下:
<?php
namespace IlluminateCache;
use Closure;
use ArrayAccess;
use DateTimeInterface;
use BadMethodCallException;
use IlluminateSupportCarbon;
use IlluminateCacheEventsCacheHit;
use IlluminateContractsCacheStore;
use IlluminateCacheEventsKeyWritten;
use IlluminateCacheEventsCacheMissed;
use IlluminateSupportTraitsMacroable;
use IlluminateCacheEventsKeyForgotten;
use IlluminateSupportInteractsWithTime;
use IlluminateContractsEventsDispatcher;
use IlluminateContractsCacheRepository as CacheContract;
/**
* @mixin IlluminateContractsCacheStore
*/
class Repository implements CacheContract, ArrayAccess
{
use InteractsWithTime;
use Macroable {
__call as macroCall;
}
/**
* The cache store implementation.
*
* @var IlluminateContractsCacheStore
*/
protected $store;
/**
* The event dispatcher implementation.
*
* @var IlluminateContractsEventsDispatcher
*/
protected $events;
protected $default = 60;
/**
* Create a new cache repository instance.
*
* @param IlluminateContractsCacheStore $store
* @return void
*/
public function __construct(Store $store)
{
$this->store = $store;
}
public function has($key)
{
return ! is_null($this->get($key));
}
public function get($key, $default = null)
{
if (is_array($key)) {
return $this->many($key);
}
$value = $this->store->get($this->itemKey($key));
// If we could not find the cache value, we will fire the missed event and get
// the default value for this cache value. This default could be a callback
// so we will execute the value function which will resolve it if needed.
if (is_null($value)) {
$this->event(new CacheMissed($key));
$value = value($default);
} else {
$this->event(new CacheHit($key, $value));
}
return $value;
}
public function pull($key, $default = null)
{
return tap($this->get($key, $default), function ($value) use ($key) {
$this->forget($key);
});
}
protected function event($event)
{
if (isset($this->events)) {
$this->events->dispatch($event);
}
}
/**
* Set the event dispatcher instance.
*
* @param IlluminateContractsEventsDispatcher $events
* @return void
*/
public function setEventDispatcher(Dispatcher $events)
{
$this->events = $events;
}
public function __call($method, $parameters)
{
if (static::hasMacro($method)) {
return $this->macroCall($method, $parameters);
}
return $this->store->$method(...$parameters);
}
public function __clone()
{
$this->store = clone $this->store;
}
}
从源码可以看出, IlluminateCacheRepository
实现了代理模式, 具体的实现是交由 IlluminateContractsCacheStore
来处理, Repository
主要作用是
- 提供一些便捷操作(可以理解为语法糖)
- Event 事件触发, 包括缓存命中/未命中、写入/删除键值
Store
IlluminateContractsCache
缓存驱动是实际处理缓存如何写入/读取/删除的类, 接口内容如下:
<?php
namespace IlluminateContractsCache;
interface Store
{
public function get($key);
public function many(array $keys);
public function put($key, $value, $minutes);
public function putMany(array $values, $minutes);
public function increment($key, $value = 1);
public function decrement($key, $value = 1);
public function forever($key, $value);
public function forget($key);
public function flush();
public function getPrefix();
}
具体的实现类有:
ApcStore
ArrayStore
NullStore
DatabaseStore
FileStore
MemcachedStore
RedisStore