Laravel 的缓存源码解析

栏目: PHP · 发布时间: 6年前

内容简介:Last-Modified: 2019年5月10日14:17:34Laravel 支持多种缓存系统, 并提供了统一的api接口.(Laravel 5.5)默认支持的存储驱动包括如下:

Last-Modified: 2019年5月10日14:17:34

前言

Laravel 支持多种缓存系统, 并提供了统一的api接口.

(Laravel 5.5)默认支持的存储驱动包括如下:

  • file (默认使用)
  • apc
  • array (数组, 测试用)
  • database (关系型数据库)
  • memcached
  • redis

默认的缓存配置文件在 config/cache.php

参考链接:

使用

直接使用 Laravel 为我们提供的Facade

use Illuminate\Support\Facades\Cache;
$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/lara...

源码

Laravel 中常用 Cache Facade 来操作缓存, 对应的实际类是 Illuminate\Cache\CacheManager 缓存管理类(工厂).

Cache::xxx()

我们通过 CacheManager 类获取持有不同存储驱动的 Illuminate\Cache\Repository

CacheManager::store($name = null)

Repository 仓库类代理了实现存储驱动接口 Illuminate\Contracts\Cache\Store 的类实例.

Cache Facade

首先从 Cache Facade 开始分析, 先看一下其源码:

<?php

namespace Illuminate\Support\Facades;

/**
 * @see \Illuminate\Cache\CacheManager
 * @see \Illuminate\Cache\Repository
 */
class Cache extends Facade
{
    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor()
    {
        return 'cache';
    }
}

在配置文件 config\app.php 中定义了 Cache 服务提供者

//...
'providers' => [
        // ......
        Illuminate\Cache\CacheServiceProvider::class,
        // ......
    ],
//...

Illuminate\Cache\CacheServiceProvider 源文件:

<?php

namespace Illuminate\Cache;

use Illuminate\Support\ServiceProvider;

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 关联的项是 Illuminate\Cache\CacheManager , 也就是我们通过 Cache Facade 实际调用的是 CacheManager 实例的方法.

CacheManager

<?php

namespace Illuminate\Contracts\Cache;

interface Factory
{
    /**
     * Get a cache store instance by name.
     *
     * @param  string|null  $name
     * @return \Illuminate\Contracts\Cache\Repository
     */
    public function store($name = null);
}

CacheManager 实现了 Illuminate\Contracts\Cache\Factory 接口(↑), 即实现了一个简单工厂, 传入存储驱动名, 返回对应的驱动实例.

CacheManager实现的简单工厂接口方法:

<?php

namespace Illuminate\Cache;

use Closure;
use InvalidArgumentException;
use Illuminate\Contracts\Cache\Store;
use Illuminate\Contracts\Cache\Factory as FactoryContract;
use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;

/**
 * @mixin \Illuminate\Contracts\Cache\Repository
 */
class CacheManager implements FactoryContract
{
    /**
     * Get a cache store instance by name.
     *
     * @param  string|null  $name
     * @return \Illuminate\Contracts\Cache\Repository
     */
    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 \Illuminate\Contracts\Cache\Repository
     */
    protected function get($name)
    {
        return $this->stores[$name] ?? $this->resolve($name);
    }

    /**
     * Resolve the given store.
     *
     * @param  string  $name
     * @return \Illuminate\Contracts\Cache\Repository
     *
     * @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(...)
CacheManager::createXxxDriver(...)

这些方法返回的实例必须是实现了 Illuminate\Contracts\Cache\Repository 接口

本质上, CacheManager 就是一个提供了 会话级别缓存Repository 实例工厂, 同时它提供了一个 __call 魔术方法, 以便快速调用默认缓存驱动.

$value = Cache::store('file')->get('foo');

// 通过 _call, 调用默认缓存驱动的 get 方法
$value = Cache::get('key');

Repository

Illuminate\Contracts\Cache\Repository 接口

<?php

namespace Illuminate\Contracts\Cache;

use Closure;
use Psr\SimpleCache\CacheInterface;

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相应的实现类: Illuminate\Cache\Repository

Illuminate\Cache\Repository 部分代码如下:

<?php

namespace Illuminate\Cache;

use Closure;
use ArrayAccess;
use DateTimeInterface;
use BadMethodCallException;
use Illuminate\Support\Carbon;
use Illuminate\Cache\Events\CacheHit;
use Illuminate\Contracts\Cache\Store;
use Illuminate\Cache\Events\KeyWritten;
use Illuminate\Cache\Events\CacheMissed;
use Illuminate\Support\Traits\Macroable;
use Illuminate\Cache\Events\KeyForgotten;
use Illuminate\Support\InteractsWithTime;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Contracts\Cache\Repository as CacheContract;

/**
 * @mixin \Illuminate\Contracts\Cache\Store
 */
class Repository implements CacheContract, ArrayAccess
{
    use InteractsWithTime;
    use Macroable {
        __call as macroCall;
    }

    /**
     * The cache store implementation.
     *
     * @var \Illuminate\Contracts\Cache\Store
     */
    protected $store;

    /**
     * The event dispatcher implementation.
     *
     * @var \Illuminate\Contracts\Events\Dispatcher
     */
    protected $events;

    protected $default = 60;

    /**
     * Create a new cache repository instance.
     *
     * @param  \Illuminate\Contracts\Cache\Store  $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  \Illuminate\Contracts\Events\Dispatcher  $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;
    }
}

从源码可以看出, Illuminate\Cache\Repository 实现了代理模式, 具体的实现是交由 Illuminate\Contracts\Cache\Store 来处理, Repository 主要作用是

  1. 提供一些便捷操作(可以理解为语法糖)
  2. Event 事件触发, 包括缓存命中/未命中、写入/删除键值

Store

Illuminate\Contracts\Cache 缓存驱动是实际处理缓存如何写入/读取/删除的类, 接口内容如下:

<?php

namespace Illuminate\Contracts\Cache;

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

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Coding the Matrix

Coding the Matrix

Philip N. Klein / Newtonian Press / 2013-7-26 / $35.00

An engaging introduction to vectors and matrices and the algorithms that operate on them, intended for the student who knows how to program. Mathematical concepts and computational problems are motiva......一起来看看 《Coding the Matrix》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具