PHP怎么实现Eloquent Attribute Caching属性缓存_Laravel减少重复计算开销【技巧】
PhpStorm 是 JetBrains 推出的专业 PHP 集成开发环境,可在 Mac 上完成代码编写、智能检查、重构、调试、测试和数据库管理。它支持主流 PHP 框架、Composer、Git、Docker 与远程解释器。
Eloquentaccessor每次访问都会重新计算,不适合耗时逻辑。通过私有属性加惰性初始化实现单实例内缓存,可避免重复计算。关联变更时需手动重置缓存。跨请求场景应使用LaravelCache::remember(),并在模型事件中清除对应缓存。
关于 Eloquent accessor 的性能问题,有一个核心判断:getXXXAttribute 方法真的是不适合放什么耗时逻辑的。为什么这么讲?因为每次你访问这个属性,哪怕是在同一个模型实例的生命周期内,它都会老老实实地重新执行一遍。
比如你在 getFullNameAttribute 里想拼接一个在数据库里并不存在的字段——你猜怎么着?每次访问它都会重新算一遍。如果这个拼接操作里还涉及调用外部 API、做复杂的数组遍历,那重复触发、反复计算,就纯粹是性能浪费了。
更隐蔽的问题是:Eloquent 并不会自动帮你缓存 accessor 的返回值,也不会敏感地察觉到内部逻辑是不是“幂等”的。你可能会想手动加 $this->attributes['full_name'] 来赋值,但真的不行——因为 accessor 本质上是只读的计算逻辑,往里面写入数据会直接污染原始属性。这一污染,后续你去调 toArray() 或者 sa ve(),很可能就跑偏了。
所以,下面这些情况最好坚决避免:
- 不要在 accessor 里查库、发 HTTP 请求、解密大字符串
- 不要试图用
$this->setAttribute('xxx', $val)来缓存结果——这会破坏数据一致性 - 如果实在要延迟计算并且复用,那必须自己来管理生命周期和缓存边界
用私有属性 + 惰性初始化实现单实例内缓存
最轻量、零依赖的方案,其实很简单:在模型类里声明一个私有属性(比如 $fullNameCache),然后在 accessor 中判断一下——已经算过了就直接返回,没算过就执行计算再赋值。这就行了。
class User extends Model{
private $fullNameCache;
public function getFullNameAttribute()
{
if ($this->fullNameCache !== null) {
return $this->fullNameCache;
}
// 这里放真正耗时逻辑,比如:
$this->fullNameCache = trim($this->first_name . ' ' . $this->last_name);
return $this->fullNameCache;
}
}
有几个细节值得注意:
- 缓存变量必须是
private,避免被外部误改或序列化时带出去 - 不能用
static,否则不同User实例会互相污染,影响数据准确性 - 如果属性依赖其他动态字段(比如关联模型变化),需要手动重置该缓存
关联变更时如何清空缓存
当 accessor 依赖了关联模型(比如 $this->posts->count()),而你在当前请求中又修改了 posts 数据,那缓存就过期了。Eloquent 不会自动通知你,你得手动干预。
常见做法是:在关联更新后显式重置缓存变量。
- 在
attach()/detach()后手动设$this->fullNameCache = null - 监听模型事件(如
sa ved),检查是否影响相关字段,再清缓存 - 更稳妥的做法:把缓存逻辑抽成独立方法,调用处统一控制生命周期,而不是全塞在 accessor 里
举个例子:
public function refreshFullNameCache()
{
$this->fullNameCache = null;
return $this;
}
// 使用时
$user->posts()->attach($post);
$user->refreshFullNameCache();
需要跨请求缓存?别硬套 Eloquent accessor
如果“减少重复计算”指的是跨 HTTP 请求的场景(比如首页多次显示用户头衔),那 Eloquent 层面的缓存其实意义不大——模型实例早就销毁了。这时候应该换思路:
- 用 Lara vel 的
Cache::remember()做键值缓存,key 包含模型 ID 和版本标识(比如"user:{$id}:full_name:v2") - 在模型的
sa ved事件中主动清除对应缓存 - 避免在 accessor 内直接调用
Cache::get()——它可能触发 IO,而且违背了“计算属性应该轻量”的设计直觉
说到底,真正该放在 accessor 里的,只是“本实例内不重复算”这样的小优化;跨请求的一致性,得靠应用层的缓存策略来兜底。
容易被忽略的是缓存键的设计。ID 相同但业务含义不同(比如审核前后的头衔不一样)时,v1/v2 版本号或者逻辑的 hash 必须跟着变,否则缓存雪崩或者脏读就容易出现了。
WPS Office是一款面向macOS用户的综合办公套件,将文字处理、电子表格、演示文稿、PDF工具、模板与云协作整合在同一应用中。它兼容常见Microsoft Office格式,支持Intel及Apple芯片Mac,基础功能可免费使用,
Shapr3D是一款面向工业设计、机械工程、建筑概念和三维打印工作流的CAD软件。Mac版采用Parasolid建模内核,支持草图约束、实体建模、工程图、可视化渲染及常见CAD格式交换,并可通过账户在多台设备之间同步项目。
REAPER是Cockos开发的数字音频工作站,提供多轨音频与MIDI录制、剪辑、处理、混音和母带制作工具。Mac版兼容Intel与Apple芯片,支持AU、VST、VST3、CLAP等插件格式,并提供高度可定制的工作流程。
Adobe Photoshop 是面向摄影师、设计师和内容创作者的专业图像处理工具,可在 Windows 上完成照片修饰、选区抠图、图层合成、文字排版、绘画及生成式编辑。软件采用订阅授权,由 Creative Cloud 管理安装、更新与许
Adobe InDesign 是面向印刷与数字出版的专业页面排版工具,可制作书籍、杂志、宣传册、海报、交互式 PDF 和电子书。它提供精细的文字样式、多页面管理、印前检查及多格式输出能力,并能与 Photoshop、Illustrator
Adobe Illustrator 是用于绘制矢量图形、插画、图标、徽标和版式的专业设计工具。它以路径和锚点为核心,作品放大后仍能保持清晰,并提供画板、文字、渐变、图像描摹及精确变换等功能,适合品牌视觉、印刷物料、数字界面和商业插画创作。













