ThinkPHP必须用Adapter封装第三方SDK,因为不封装会导致控制器充斥渠道判断和重复校验逻辑,耦合业务与协议;Adapter仅提供verify()、getOrderId()、getNotifyId()、buildSuccessResponse()四个核心方法,专注请求翻译,解耦渠道差异。

ThinkPHP里为什么必须用Adapter封装第三方SDK
因为不封装就会在控制器里堆满渠道判断和重复校验逻辑,比如if ($channel === 'wechat')套一层XML解析,再套一层签名验证;换成支付宝又要重写一遍form解包+RSA验签。更麻烦的是,每个渠道的响应格式、幂等字段、失败返回规则都不一样,硬写进去等于把业务代码和渠道协议耦合死。
Adapter不是为了“高大上”,是让PayController::notify()只做三件事:调$adapter->verify()、查订单、更新状态。渠道差异全推给适配器类自己扛。
Adapter接口该定义哪些方法才够用
别照搬设计模式教科书,只留真正被主流程调用的接口。根据微信、支付宝、银联回调的真实需求,这几个方法足够:
-
verify():必须返回bool,内部完成签名验证+参数完整性检查 -
getOrderId():提取业务订单号,不能是渠道单号(如out_trade_no) -
getNotifyId():关键!微信v3叫result_notify_id,支付宝叫notify_id,用于数据库唯一索引防重入 -
buildSuccessResponse():返回纯字符串,微信要"success",支付宝要空字符串或"success",不能带或BOM
别加handle()或updateOrder()——那是Service层的事,Adapter只负责“翻译”请求。
立即学习“PHP免费学习笔记(深入)”;
TP6下Adapter类怎么放、怎么加载才不报Class not found
TP6彻底依赖Composer自动加载,vendor()和import()已失效。Adapter类必须走PSR-4规范:
- 类文件放在
app/Adapters/WechatNotifyAdapter.php,命名空间声明为appAdapters - 在
composer.json的"autoload"段加上:"app\Adapters\": "app/Adapters/" - 改完立刻执行
composer dump-autoload -o,否则新增类永远找不到 - 构造函数只接收
array $rawInput和配置数组,禁止依赖Request对象或容器
如果SDK本身没命名空间(比如老版微信支付SDK),就别塞进Adapter类里硬改——单独用"files"方式加载它,Adapter只负责调用。
微信和支付宝Adapter实现时最容易踩的坑
两个渠道表面都是“验签+取订单号”,但细节差得远:
- 微信回调是XML,
file_get_contents('php://input')后必须用simplexml_load_string()转数组,且sign字段要从原始XML字符串计算,不能从解析后数组里取 - 支付宝回调可能是GET或POST,
$_POST可能为空,得统一用$_REQUEST或file_get_contents('php://input')兜底;验签前必须用ksort()对参数排序,漏掉这步100%失败 - 支付宝的
notify_id只能用一次,验签成功后必须立刻保存到缓存或DB,二次回调直接拒绝;微信的result_notify_id则可重复使用,但需配合timestamp+nonce_str组合去重 - 所有Adapter的
buildSuccessResponse()必须用echo或return原样输出,不能json_encode(),不能var_dump(),否则微信会持续重发
最常被忽略的一点:Adapter类里不能有任何exit或die,框架需要完整生命周期来记录日志、触发事件。失败只靠buildFailureResponse()返回字符串,由控制器决定是否抛异常。



















