thinkphp项目重构核心是解耦权限、数据库与业务逻辑:权限校验统一收口至permissionservice::can(),禁用硬编码;数据库操作封装进repository+dto;菜单与权限彻底分离,路由显式标注权限要求。

ThinkPHP项目重构不是为了换新壳,而是让权限、数据库、业务逻辑这些关键链路不再互相咬死——一旦角色权限硬编码在配置里、控制器里直接查库、模型里拼SQL,后续加租户、换认证方式、做灰度发布就全是硬磕。
权限校验必须收口到 PermissionService::can()
常见错误是控制器里写 $this->auth->hasAccess('order:delete') 或 Auth::check('user/edit'),结果权限规则散落在二十个方法开头,改一个要 grep 全局,测试用例根本没法写。
- 所有鉴权统一走
PermissionService::can($user, $action, $resource),$action严格用小写冒号格式(如'article:publish'),禁用驼峰或空格 -
$resource接受模型实例或 ID,Service 内部自动 resolve,控制器不负责查一遍再传 - 拒绝时抛
PermissionDeniedException,由全局异常处理器返回 403,不写if (!... ) die()或 return false - 缓存必须按 tag 管理:
Cache::tag('permission')->get($key),更新某角色权限时只删对应 tag,不影响其他角色缓存
数据库操作必须剥离控制器,封装进 Repository + DTO
控制器里出现 Db::table('user')->where(...)->select() 或 UserModel::with('orders')->find($id) 是典型信号:数据访问逻辑和路由绑定太紧,一动全抖。
- 新建
app/repository/UserRepository.php,把关联查询、分页组装、软删除过滤等封装进去,方法命名语义化(如findActiveUserWithOrders(int $id)) - DTO 只用于输入/输出,不带行为;例如
UserCreateDTO仅含name、email、role_ids字段,验证逻辑交由独立的UserCreateValidator - 禁止在模型的访问器(如
getPermissionsAttribute())里触发 N+1 查询,一律预加载或由 Repository 显式提供 - 主从分离、多库路由等配置不写死在 Repository,通过 DI 容器注入不同
PDO实例或ConnectionManager
菜单与权限彻底解耦,前端按钮权限靠 getAllowedActions() 驱动
把菜单当权限看(比如认为有 'menu:user' 就该显示用户菜单)是高危耦合——菜单可见性取决于组织架构、设备类型、语言包,而权限只管“能不能点”。混在一起,国际化时改菜单就得同步改权限表。
- 菜单数据存在
menu表,字段含route、icon、sort、visible_role_ids(可为空),**不存 permission 字段** - 后端构建菜单时调
MenuService::buildForUser($user):先查visible_role_ids包含该用户的菜单项,再对每项调PermissionService::can()判断是否启用href或显示操作按钮 - 前端按钮级权限不靠后端传布尔值,而是请求
/api/user/allowed-actions拿回扁平数组(如['user:create', 'order:export']),自行控制按钮显隐 - 所有路由定义必须显式标注权限要求,例如在
route/app.php中用中间件参数:->middleware('permission:article:publish'),避免漏配
重构最难的不是写新代码,而是找到所有隐式权限调用点——比如某个导出 Excel 的接口没走中间件,但内部却手动查了 user.role 做判断;这类逻辑藏得深,不全局扫描+日志埋点,上线后必出权限绕过。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











