如何优化两层多对多关联下的用户权限校验实现代码
现有实现存在的问题
- 关联预加载不完整:仅加载了
roles关联,未嵌套加载roles.permissions,遍历角色权限时会产生N+1次SQL查询,性能损耗大 - 存在逻辑bug:代码中遗留的
dd('hier 2')调试语句,会在第一个权限匹配失败时直接终止程序运行,导致后续权限校验逻辑完全无法执行 - 时间复杂度高:两层foreach循环加上每次遍历都调用
array_filter遍历待校验权限数组,时间复杂度达到O(mnk)(m为用户所属角色数、n为单角色对应权限数、k为待校验权限数),效率极低 - 封装冗余:自定义的
getFilteredArray过滤方法完全可以用PHP内置的in_array方法替代,不需要单独封装做遍历过滤
优化方案
从代码特征判断你使用的是Laravel框架的Eloquent模型,以下提供两种适配不同场景的优化实现:
方案1:基于集合的内存校验(适合中小权限量级场景)
优化后代码:
public function hasPermissions(array $permissions = []): bool { // 空权限入参可根据业务需求调整返回值,此处和原逻辑对齐返回false if (empty($permissions)) { return false; } // 一次性预加载所有嵌套关联,仅执行2次SQL查询 $this->loadMissing('roles.permissions'); // 拍平所有角色的权限,直接判断和待校验权限是否有交集 return $this->roles ->pluck('permissions') ->flatten(1) ->pluck('permission') ->intersect($permissions) ->isNotEmpty(); }
优化点说明:
- 嵌套关联预加载避免了N+1查询问题
- 去掉所有手写循环,用Laravel内置集合方法完成权限提取和匹配,逻辑简洁可读性高
- 时间复杂度降低为O(m*n + k),性能提升明显
方案2:数据库层直接校验(适合大权限量级场景)
如果用户关联的角色和权限量级很大,不需要把所有权限加载到内存处理,可以直接通过EXISTS查询完成校验,性能最高:
public function hasPermissions(array $permissions = []): bool { if (empty($permissions)) { return false; } // 仅执行1次EXISTS查询,无需返回任何权限数据 return $this->roles()->whereHas('permissions', function ($query) use ($permissions) { $query->whereIn('permission', $permissions); })->exists(); }
如果你的业务需求是校验用户拥有所有传入的权限,只需将方案1的交集判断改为intersect($permissions)->count() === count($permissions),方案2则改为统计匹配的权限数量和传入权限数量是否相等即可。
内容的提问来源于stack exchange,提问作者GekkeGlenn-Dev
相关产品推荐
相关产品推荐

