可複用的快取元件

liuyuit發表於2021-07-12

對一些高頻資料,我們都需要快取起來,以免 MySQL 壓力過大。
一般的寫法是先判斷快取中是否有資料,沒有資料再將資料查出來,再快取起來。
其實可以用一個函式將這個過程封裝起來
helper.php

if (!function_exists('remember')) {
    /**
     * 快取資料
     *
     * @param $uniqId
     * @param $dataSource mixed|\Closure 資料來源
     * @param int $ttl
     * @return mixed|string
     */
    function remember($uniqId, $dataSource, int $ttl = 600)
    {
        $redisKey = 'remember:' . $uniqId;
        $result = Redis::get($redisKey);

        if ($result) {
            return unserialize($result);
        }

        if ($dataSource instanceof \Closure) {
            $result = $dataSource();
        } elseif (is_array($dataSource) && isset($dataSource[0]) && is_object($dataSource[0])) {
            $object = $dataSource[0];
            $function = $dataSource[1];
            $args = $dataSource[2] ?? [];
            $result = call_user_func_array([$object, $function], $args);
        } else {
            $result = $dataSource;
        }

        Redis::setex($redisKey, $ttl, serialize($result));
        return $result;
    }
}
if (!function_exists('forget')) {
  /**
 * 清除已快取的資料
  *
 * @param $uniqId
  * @return int
 */  function forget($uniqId): int
  {
  $redisKey = 'remember:' . $uniqId;
 return Redis::del($redisKey);
  }
}

使用方法

$linkData = remember("player_link_data:{$gid}:{$uid}", function () use ($gid, $uid) {
                $player = Player::whereUid($uid)->whereGid($gid)->first();
                return [
                    'admin_id' => $player->admin_id,
                    'team_id' => $player->team_id,
                ];
            });

快取物件執行某個方法後的結果

除了可以將回撥函式的執行結果快取,還可以將物件執行某個方法後的結果快取起來
app/Services/Cache/CacheBase.php

<?php

namespace App\Services\Cache;

use Illuminate\Support\Arr;

abstract class CacheBase
{
    /**
     * 全部資料
     * @var array
     */
    protected array $all;

    /**
     * 快取的唯一 id
     * @var string
     */
    protected string $uniqid;

    protected int $ttl = 600;

    /**
     * 獲取全部資料
     * @return array
     */
    abstract protected function allData(): array;

    /**
     * 獲取全部資料並快取
     * @return mixed|string
     */
    public function all()
    {
        $all = remember($this->uniqid, [$this, 'allData'], $this->ttl);
        return $all;
    }

    /**
     * 清除資料快取
     * @return int
     */
    public function clean()
    {
        return forget($this->uniqid);
    }

    public function get($key)
    {
        $all = $this->all();
        $result = $all[$key] ?? null;

        return $result;
    }

    public function only($keys)
    {
        $all = $this->all();
        $result = Arr::only($all, $keys);

        return $result;
    }

    public function __get($property)
    {
        if (!isset($this->all)) {
            $this->all = $this->all();
        }

        $result = $this->all[$property] ?? null;

        return $result;
    }
}

app/Services/Cache/User/BanIpList.php

<?php

namespace App\Services\Cache\User;

use App\Models\Config\BanIp;
use App\Services\Cache\CacheBase;

class BanIpList extends CacheBase
{
    protected string $uniqid;

    public function __construct()
    {
        $this->uniqid = 'BannedIp:';
    }

    public function allData(): array
    {
        return BanIp::where('release_time', '>', BanIp::raw('now()'))
            ->where('enable', '=', 1)
            ->pluck('ip')->toArray();
    }
}
use App\Services\Cache\User\BanIpList;

$banIPObj = new BanIpList();
$banIPList = $banIPObj->all();
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章