thinkphp 5.1 应严格遵循分层职责:controller 仅调度与参数校验,禁止出现 db::table();验证逻辑须独立成类,业务规则移至 service;service 需语义化命名、dto 传参、统一 result 返回;模板禁止嵌入逻辑,状态与格式化须前置处理。

ThinkPHP 5.1 的 Controller 层如果直接调用 Db::table()、混写验证逻辑、塞满业务判断,那它早就不是控制器,而是“缝合怪调度中心”——这种代码维护成本会随迭代指数级上升,不是“难维护”,是“不敢动”。
Controller 里出现 Db::table() 就该立刻停手
TP5.1 的 Db 类是数据访问层的快捷入口,但它不该出现在 Controller 中。一旦你看到类似这样的代码:
$user = Db::table('user')->where('id', $id)->find();
说明职责已经泄漏:Controller 承担了数据获取 + 基础过滤 + 状态组装三重任务,后续加个字段映射、改个关联查询、补个缓存逻辑,都得改 Controller,测试也得重写。
- 正确路径是:Controller → Service → Repository(或 Model)
- Service 层负责组合逻辑(如“查用户 + 查其最近3条订单 + 拼装头像URL”),Repository 负责单表 CRUD
- TP5.1 中可建
app\common\repository\UserRepository,把Db::table('user')封装进它的findById()方法里 - Controller 只保留
$this->userService->getProfile($id)这类语义清晰的调用
validate() 不是万能胶,别往 request() 上硬贴
TP5.1 的 validate() 很方便,但把它当补丁打在 request()->param() 后面,很快就会失控。常见症状包括:
- 同一个字段在多个方法里重复定义规则(如
'email' => 'require|email'出现在 5 个 Controller 方法中) - 规则里塞业务逻辑(
'password' => 'require|checkOldPassword:uid',把密码校验耦合进验证器) - 验证失败后手动拼
['code'=>400, 'msg'=>'xxx'],和统一响应结构冲突
建议做法:
- 每个业务动作建独立验证器类,如
app\validate\User\UpdateProfileValidate - 验证器只做字段格式、长度、必填等基础检查;业务规则(如“新邮箱不能与旧邮箱相同”)移入 Service 层
- 在基类
Controller中统一拦截ValidateException,转为Result::fail(400, $e->getMessage())
不要让 service 层变成 controller 的镜像副本
很多重构只是把 Controller 里的代码剪切粘贴到 Service,方法名照抄(index()、save()、delete()),参数一模一样,这没解决任何问题——只是把“胖 Controller”换成了“胖 Service”。
真正有效的 Service 接口设计应满足:
- 方法名体现业务意图,而非 HTTP 动词:
createUserWithInviteCode()比save()明确得多 - 参数尽量聚合:用
UserCreateDTO对象传参,而不是一堆$name, $email, $phone, $source - 返回值类型稳定:不返回
array或bool,统一用Result包装,即使成功也带data字段(空数组或 null) - 事务边界清晰:一个 Service 方法对应一个完整业务用例,跨表操作必须包裹
Db::transaction()
View 层嵌套 PHP 逻辑是重构最大盲区
TP5.1 的模板引擎支持 {:function()} 和 {php}...{/php},但这是重构时最常被忽略的腐化点。例如:
{volist name="list" id="vo"}{:date('Y-m-d', $vo.create_time)}{if $vo.status == 1}已启用{else}已禁用{/if}{/volist}
这类逻辑本该由 Controller 或 Service 提前处理好,比如:
- 把
create_time格式化成字符串字段塞进$vo,模板只做展示 - 状态码转文字映射放到 Service 层(
statusText($vo.status)),Controller 组装进data返回 - 模板里只留纯变量插值:
{$vo.formatted_create_time} {$vo.status_text}
否则,前端改个日期格式、运营要加个“试用期状态”标签,都得翻模板、找 PHP 片段、改逻辑、再测——这不是前端工作,是后端调试。
最难重构的从来不是哪行代码写错了,而是那些“跑得通、看起来没问题、但谁都不敢删”的胶水逻辑。它们藏在验证器里、混在模板中、躺在 Service 方法命名背后。重构 TP5.1 项目,关键不是换框架,是让每一层只说自己的语言:Controller 说“我要什么”,Service 说“这事怎么干”,Repository 说“数据在哪”,View 说“我怎么画”。











