Home > other >  Best way to avoid reloading from cache repititively?
Best way to avoid reloading from cache repititively?

Time:12-19

Let's say we have a method of an Class that is being called in iteration n times, and the method in itself has a statement that pulls data from a cache system - Redis.

Now if this method is called n times the cache is also hit n times leading to a continuous fetch and unserializing of the same data n times which in the case of an interpreter like PHP consumes a good amount of time & CPU.

Passing the cached data to this method could also be a no as we might instantiate n number of instances of this class.

So is there a way where we can avoid hitting the cache multiple times in the context of a Class/Object instead if we can use the static properties of the Object to hold the value?

CodePudding user response:

If you are in the opinion that you should not use a service-class (which the other answer explains),
then consider using PHP's $GLOBALS variable to backup the loaded-Cache (instead of adding yet another custom static variable).

Examples

Maybe backup once for all:

In Laravel's AppServiceProvider.php file, do something like:

<?php

namespace App\Providers;

// ...

use Illuminate\Support\Facades\Cache;

class AppServiceProvider extends ServiceProvider
{

    // ...

    public function boot()
    {
        $keyList = [
            'my-unique-key',
            'my-other-key',
        ];

        foreach($keyList as $key) {
            $GLOBALS['cache-' . $key] = Cache::get($key);
        }
    }
}

Finally, use $GLOBALS['cache-my-unique-key'] anywhere required.

Or, backup per class:

<?php

use Illuminate\Support\Facades\Cache;

class YourClass {
    private $myData;

    public function __construct()
    {
        $key = 'my-unique-key';

        $value = & $GLOBALS['cache-' . $key];
        if ( ! isset($value)) {
            $value = Cache::get($key);
        }

        $this->myData = $value;
    }

    // Finally, use `$this->myData` anywhere in this same class.
}

Note that as you may already know, in both cases we use 'cache-' prefix to not overwrite anything by mistake.

CodePudding user response:

You can use static properties to store the cached data and use access it same.

class CacheClass
{
    private static $cachedData;

    public function retrieveData()
    {
        if (!isset(self::$cachedData)) {
            // re-assign the value
            self::$cachedData = fetchDataFromCache();
        }
        
        return self::$cachedData;
    }
}

CodePudding user response:

First, write a service class that:

  • Provides getter, which:
    • Loads required value from cache (based on unique-key),
    • But also backups the loaded-value,
    • Finally, returns backupped-value instead of re-loading from cache.
  • Provides setter which updates both backup and cache.

Then simply use Laravel's feature to inject and/or get instance of said service-class.

(I write and/or say "backupped" instead of "backed up", because dictionary is wrong, as prove:

  • "backupped cake" remains it's meaning,
  • while "backed up cake" is confusing.)

Example

<?php

namespace App\Services;

use Illuminate\Support\Facades\Cache;

class MyCacheService
{
    protected $backupMap = [];

    /**
     * Requests an instance of this-class from Laravel. 
     *
     * @return MyCacheService|null
     */
    public static function instance()
    {
        return \Illuminate\Support\Facades\App::make(MyCacheService::class);
    }

    public function get($key)
    {
        $backup = & $this->backupMap[$key];
        if ( ! isset($backup)) {
            $backup = $this->rawGet($key);
        }
        return $buckup;
    }

    public function set($key, $value)
    {
        $this->rawSet($key, $value);
        $this->backupMap[$key] = $value;
    }

    /** Loads from cache */
    private function rawGet($key)
    {
        // ... your normal loading from cache logic goes here,
        // but as sub-example:

        return Cache::get($key);
    }

    /** Saves into cache */
    private function rawSet($key, $value)
    {
        // ... your normal saving into cache logic goes here,
        // but as sub-example:
        Cache::set($key, $value);
    }
}

Usage:

use App\Services\MyCacheService;
use Illuminate\Support\Facades\App;

// ...

// Get instance once, like:
$cacheService = MyCacheService::instance();

// Or like:
/** @var MyCacheService|null $cacheService */
$cacheService = App::make(MyCacheService::class);

// Finally, reuse as many times as required, like:
$myValue = $cacheService->get('my-unique-key');

$myOtherValue = $cacheService->get('my-other-key');

Note that Laravel stores the class's instance for us, else one could use private static property named $instance, and return that from instance() method.

WARNING: as you may already know, maybe replace rawGet and rawSet's logic.

Also, place MyCacheService.php file (which's source is above) in app/Services folder.

  • Related