Preface
When I was working on a project some time ago, I wanted to cache the Model::find method without changing the method signature. And want to plug and play. I won’t say much below, let’s take a look at the detailed introduction together.
1. Let’s first look at what the framework does when we call the find method?
Find the code for Illuminate\Database\Eloquent\Model, search for find, there is no method. It seems that I have left __callStatic. There is only one line of code in this method:
return (new static)->$method(...$parameters);
static refers to the class that calls the static method (if UserModel::find(1), static represents the UserModel class). It seems that an object is instantiated and the member method is called.
2. Analyze how to gracefully insert a kick in the middle
In order to be able to go to our cache first when calling find, we need to override the __callStatic method and detect that if it is the find method, the data in the cache will be returned first.
In addition, in order to achieve the effect of plug and play, we use the inheritance method, but use Trait. The core logic is as follows:
public static function create($data = null){ if ($data == null){ return null; } $instance = new static; foreach ($data as $key => $value){ $instance[$key] = $value; } return $instance; } /** * If the method is find($id, $nocache) * * @param string $method * @param array $parameters * @return mixed */ public static function __callStatic($method, $parameters) { if ($method == 'find'){ // Get data from cache $obj = static::create(json_decode(Redis::get(static::getCacheKey($parameters[0])), true)); if (null == $obj){ $obj = (new static)->$method(...$parameters); if (null == $obj){ return null; } else { $key = static::getCacheKey($parameters[0]); // Set cache and expiration time Redis::set($key, $obj); Redis::expire($key, static::$expire_time); return $obj; } } else { $obj->exists = true; return $obj; } } else if($method == 'findNoCache'){ $method = 'find'; return (new static)->$method(...$parameters); } return (new static)->$method(...$parameters); } private static function getCacheKey($id){ $name = str_replace('\\', ':', __CLASS__); return "{$name}:{$id}"; }
The general logic has been introduced above: override the __callStatic method and determine that if find is called, it will go to cache (no cache, and cache needs to be set after query). Another new findNoCache method has been added.
3. Detail supplement
When modifying (or deleting) data (calling the save method), cached content needs to be deleted.
private static function clearCache($id){ Redis::del(self::getCacheKey($id)); } /** * when save, should clear cache * @param array $options */ public function save(array $options = []){ static::clearCache($this[$this->primaryKey]); return parent::save($options); } // delete I'll write the method temporarily,Similar content save method
How to use. In the Model class that needs to use find cache, adding one line is enough.
class User extends BaseModel { use MemoryCacheTrait; }
Go and try it.
Summarize
The above is the entire content of this article. I hope that the content of this article has certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support.