skip to Main Content

Consider having a Class whose method 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.

Hence is there a way where we can avoid hitting the cache multiple times in the context of a Class and/or Object?

Maybe we can somehow use static properties of the Object to hold the value?

3

Answers


  1. 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;
        }
    }
    
    Login or Signup to reply.
  2. 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.

    Example

    <?php
    
    namespace AppServices;
    
    use IlluminateSupportFacadesCache;
    
    class MyCacheService
    {
        protected $backupMap = [];
    
        /**
         * Requests an instance of this-class from Laravel. 
         *
         * @return MyCacheService|null
         */
        public static function instance()
        {
            return IlluminateSupportFacadesApp::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 AppServicesMyCacheService;
    use IlluminateSupportFacadesApp;
    
    // ...
    
    // Get instance once, like:
    $cache = MyCacheService::instance();
    
    // Or like:
    /** @var MyCacheService|null $cache */
    $cache = App::make(MyCacheService::class);
    
    // Finally, reuse as many times as required, like:
    $myValue = $cache->get('my-unique-key');
    
    $myOtherValue = $cache->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.

    Login or Signup to reply.
  3. 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 AppProviders;
    
    // ...
    
    use IlluminateSupportFacadesCache;
    
    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 IlluminateSupportFacadesCache;
    
    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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search