问题背景接上一篇博客:Laravel模型优化-AttributeCacheHelper在添加属性缓存(attributecache)之前实现,虽然实现解决了动态重复触发SQL的问题attributes在每个请求中执行的问题,但同时也引入了一个新的问题,增加了代码量和维护成本。添加100个动态属性需要200个函数。大量使用是一场噩梦。实现缓存映射并尝试改善这个问题。现在将所有的缓存属性整合成一个数组,用cacheKey指向解析函数。首先实现一个可缓存的数组来管理属性和实体函数之间的映射。例如,balance的属性将映射到refreshBalance函数。private$cacheable=['posts_count'=>'postCount','balancde'=>'refreshBalance',];如何处理这个属性映射,可以使用PHP提供的魔术方法__get来处理,然后修改属性缓存helper的__get函数会先检查这个属性是否在缓存映射数组中。如果存在,则直接去缓存中获取数据。如果数据不存在,则执行映射函数,获取执行后的结果并缓存,反之,如果缓存映射数组中不存在该属性,则会转发给模型本身的__get魔术方法,然后进行处理。cacheable)){return$this->getCachedAttribute($key,[$this,$this->cacheable[$key]]);}返回父级::__get($key);}publicfunctiongetCachedAttribute(string$key,callable$callable){if(!array_key_exists($key,$this->cachedAttributes)){$this->setCachedAttribute($key,call_user_func($callable));}返回$this->cachedAttributes[$key];}publicfunctionsetCachedAttribute(string$key,$value){return$this->cachedAttributes[$key]=$value;}publicfunctionrefresh(){$this->cachedAttributes=[];返回父级::刷新();}}完成以上操作后,改进后的属性后缓存就不需要再定义两个函数了,只需要定义一个映射函数,然后指向需要构造的动态属性即可。实现缓存刷新,问题又来了。如果主动刷新缓存数据怎么办?尤其是在支付、提现等场景中,最后一步往往需要主动刷新缓存并再次验证。然后添加一个refreshAttributeCache函数,我们就可以主动刷新属性缓存的数据了。cacheable)){return$this->getCachedAttribute($key,[$this,$this->cacheable[$key]]);}返回父级::__get($key);}publicfunctiongetCachedAttribute(string$key,callable$callable,$refresh=false){if(!array_key_exists($key,$this->cachedAttributes)||$refresh){$this->setCachedAttribute($key,call_user_func($可调用));}返回$this->cachedAttributes[$key];}publicfunctionsetCachedAttribute(string$key,$value){return$this->cachedAttributes[$key]=$value;}publicfunctionrefresh(){$this->cachedAttributes=[];返回父级::刷新();}publicfunctionrefreshAttributeCache($key){if(array_key_exists($key,$this->cacheable)){return$this->getCachedAttribute($key,[$this,$this->cacheable[$key]],true);}}}runtestattachAttributeCacheHelpertomodel'refreshBalance'];publicfunctionrefreshBalance(){$lastTransaction=$this->transactions()->latest('id')->select('balance')->first();$balance=!is_null($lastTransaction)?$lastTransaction->余额:0;返回$余额;}}执行结果。$wallet=Wallet::find(1);for($i=0;$i<10000;$i++){//只执行一次真实有效的查询dump($wallet->balance);}//获取再次查询结果,执行SQL$balance=$wallet->refreshAttributeCache('balance');dd($余额);上面结束,解决了第一版属性缓存助手导致的定义函数难维护,不能主动刷新缓存的弱点,当然也可以逆向,标记做的属性不需要缓存,缓存其余属性。就个人而言,我更喜欢按需获取它们。呵呵,具体怎么做要看具体的业务使用场景。区别对待。
