--- description: PHP clean code rules for readable, maintainable and clear backend code globs: - "**/*.php" alwaysApply: true --- # PHP Clean Code Rules 目标:生成和修改 PHP 后端代码时,优先保证 **可读、可维护、清晰、简单、易排查**。 分层职责遵循 `Backend Layering Rules`。本规则只约束代码写法质量。 --- ## 1. 核心原则 - 优先清晰,不写炫技代码。 - 一个方法只表达一个明确动作。 - 代码应像业务流程一样容易阅读。 - 复杂逻辑必须拆成有业务语义的私有方法。 - 不要为了减少行数牺牲可读性。 - 不允许用注释弥补糟糕命名。 - 禁止无意义的 `Helper`、`Util`、`CommonService`、`Manager`。 - 禁止创建只做转发、没有业务价值的中间层。 --- ## 2. 命名规则 禁止用模糊变量名承载核心业务数据: - `$data` - `$list` - `$info` - `$tmp` - `$row` - `$result` - `$res` - `$arr` 变量、方法、类名必须表达业务含义。 推荐命名风格: - `$userInfo` - `$rebateConfig` - `$walletTransaction` - `$validBetAmount` - `$claimResult` - `getEnabledUser()` - `ensureCanClaim()` - `createWalletTransaction()` - `claimRebateInTransaction()` 布尔变量必须表达真假语义,例如 `$isEnabled`、`$isClaimed`、`$hasPermission`、`$canWithdraw`。 避免无意义方法名:`handle()`、`process()`、`doSomething()`、`getData()`、`getList()`。 如果必须使用 `handle()` / `process()`,需要有明确上下文,例如 `handlePaymentCallback()`、`processSettledBet()`。 --- ## 3. 方法规则 - 方法长度建议不超过 50 行。 - 方法嵌套不超过 3 层。 - 优先使用 early return / early throw。 - 方法参数一般不超过 3 个。 - 参数超过 3 个时,优先使用 DTO、Value Object 或专门数据结构。 - 核心业务入参不要直接使用含糊的 `array`。 - 返回 `array` 时必须结构明确,并用 PHPDoc 描述结构。 - 私有方法也必须有清晰业务语义。 - 复杂条件必须封装成有语义的方法。 - 魔法数字必须变成常量或枚举。 - 业务规则判断优先使用 `ensureXxx()` 方法。 - 不要把查询、判断、写入、返回组装全部堆在一个大方法里。 --- ## 4. Logic / Service / Model 写法 ### Logic - Logic 是业务用例入口,一个 public 方法通常对应一个业务用例。 - Logic 主方法要像读业务流程。 - Logic 私有方法必须有业务语义。 - Logic 可以查业务主体、调用 Model、调用公共 Service、做业务判断、控制事务、写业务日志、组装返回结果。 - 复杂查询条件应沉淀到 Model。 - 涉及多表写入、钱包变动、订单状态变更、活动领取、返水领取、游戏下注 / 派奖时,事务边界必须放在 Logic。 - 事务内禁止请求第三方接口、发送 MQ、发送短信、发送邮件、大量循环处理、复杂远程调用。 ### Service - Service 只放公共能力,例如第三方 SDK、center 调用、公共配置、公共计算、跨业务复用逻辑、基础设施封装。 - Service 禁止承载单业务用例编排。 - Service 禁止只做 Model 转发或 Logic 转发。 - Service 禁止为每张表创建一个 Service。 - 如果一个 Service 方法没有封装公共能力,不应创建。 ### Model - Model 负责数据查询和写入。 - Model 可以包含查询条件封装、scope、搜索器、关联关系、简单数据写入、常用查询方法。 - Model 禁止写复杂业务流程、控制事务、调用第三方接口、编排多个业务步骤。 - Model 方法命名必须表达查询或写入意图,例如 `findEnabledById()`、`existsClaimedRecord()`、`sumValidBetAmount()`、`createClaimRecord()`。 - 避免 `getData()`、`getList()`、`handle()`、`process()`。 --- ## 5. PHPDoc 与注释 Logic、Service、Model 的 public 方法建议写 PHPDoc。 以下情况必须写 PHPDoc: - 返回 `array` - 参数是复杂 `array` - 可能抛出业务异常 - 涉及状态流转 - 涉及钱包、订单、活动、游戏交易 - 方法语义不是一眼能看懂 返回 array 必须写结构: ```php /** * @return array{ * user_id: int, * nickname: string, * balance: int * } */ ``` 复杂 array 参数必须写结构: ```php /** * @param array{ * user_id: int, * amount: int, * order_no: string, * remark?: string * } $data */ ``` 涉及异常必须写 `@throws`。 不要写废话 PHPDoc。简单 getter/setter、方法名和类型已足够清晰时,不强制 PHPDoc。 注释解释为什么,不解释做什么。复杂业务、幂等处理、分布式锁、状态流转、第三方接口兼容、历史兼容逻辑必须有注释。 --- ## 6. 异常、日志、返回 - 禁止返回 `false` 表示业务失败。 - 业务失败应抛出业务异常。 - 禁止吞异常。 - 捕获异常后必须记录必要上下文;如无法处理,必须继续抛出。 - 业务异常和系统异常要区分。 - 异常信息必须清晰,不能只写 `error`、`failed`。 - 关键业务必须打日志,例如钱包变动、游戏下注、游戏派奖、支付回调、活动领取、返水领取、第三方接口异常、风控命中、重要状态变更。 - 日志必须包含关键上下文,例如 `user_id`、`order_no`、`provider_code`、`provider_tx_id`、`round_id`、`amount`、`status`、`error`。 - 日志禁止记录密码、token、secret、私钥、支付密钥、银行卡完整号码、用户隐私数据、第三方签名密钥。 - 返回结构必须明确。 - 不直接返回 Model 对象。 - 不返回临时调试字段、SQL、异常堆栈、内部配置、secret、token、sign。 --- ## 7. 幂等要求 涉及重复请求风险必须考虑幂等,包括第三方回调、钱包加减款、订单支付、活动领取、返水领取、游戏下注、游戏派奖、MQ 消费。 优先使用唯一索引保证幂等,并在代码中保留明确幂等判断。 --- ## 8. Agent 自查 完成代码前必须自查: - 命名是否清晰? - 方法是否过长? - 嵌套是否过深? - 是否有魔法数字或魔法字符串? - Logic 是否表达清晰业务流程? - Service 是否确实是公共能力? - Model 是否只做数据访问? - 多表写入是否有事务? - 是否需要幂等? - 是否吞异常? - 日志是否有关键上下文? - 是否泄露敏感信息? - 返回数据是否明确? - 是否直接返回 Model? - 返回 array 的方法是否写清楚 PHPDoc? - 复杂数组参数是否写清楚 PHPDoc? - 涉及异常的方法是否写了 `@throws`? --- ## 9. 优先级 当规则冲突时,按以下优先级处理: 1. 正确性 2. 安全性 3. 数据一致性 4. 可读性 5. 可维护性 6. 简洁性 7. 性能 除非已有明确性能瓶颈,否则不要为了性能牺牲可读性。