本文档记录在开发过程中遇到的典型错误及其解决方案,供团队参考避免重复踩坑。
在 GamePayService::orderData() 方法中,$payData['pay_amount'] 的计算依赖于 Pay::calPayAmount() 方法。当使用专属币(ptb_amt)且存在折扣时,计算结果偏高。
// Pay.php 第166-176行
$diff = bcsub($amount, $ptb_amount, 2); // 先扣除专属币
$raw_amount = bcmul($diff, $discount, 4); // 再应用折扣
$discounted = bcmul($amount, $discount, 2); // 先应用折扣
$result = bcsub($discounted, $ptb_amount, 2); // 再扣除专属币
calPayAmount() 的支付入口调整 calPayAmount() 中的计算顺序,确保先折扣后扣除。
在 api/controller/v1/Pay.php 中调用 calPayAmount() 时未传递 $discount 参数,导致折扣配置失效。
// api/controller/v1/Pay.php 第257、260行
$arrPayAmount = $payLogic->calPayAmount($amount, $ptb_amt); // 缺少 $discount
$arrPayAmount = $payLogic->calPayAmount($amount); // 缺少 $discount
$discount = 1 的默认值掩盖了参数缺失补充 $discount 参数传递:
$discount = getDiscount($member_id, $game_id, $channel_id);
$arrPayAmount = $payLogic->calPayAmount($amount, $ptb_amt, $discount);
null)生产代码中残留 dump() 调试语句,影响性能和输出。
// common.php 第639行
dump($ancestors);
// Pay.php 第550行
dump($channel);
dump(、var_dump(、print_r(用户登录时,新的设备号不会被添加到常用设备列表中,数据库中 nw_subaccount.recent_devices 字段始终只保存一个设备。
// api/controller/v1/Login.php 第594行
$memberDevice->addDevice($userinfo['id'], $gameid, $imeil, $device, false, true);
// ↑
// $onlyUpdateExisting = true
$memberDevice->addDevice($userinfo['id'], $gameid, $imeil, $device, false, false);
// ↑
// $onlyUpdateExisting = false
api/controller/v1/Login.php 登录接口MemberDevice::addDevice() 的 $onlyUpdateExisting 参数含义混淆:
true = 仅更新已存在设备,不添加新设备false = 不存在时添加新设备true,与注册接口逻辑不一致false(或使用默认值)将 Login.php 中 $onlyUpdateExisting 参数改为 false,使登录与注册保持一致,都允许添加新设备。
true/false在 GamePayService::gamePay() 方法中,$payData['real_amount'] 和 $payData['pay_amount'] 两个字段容易混淆,需要明确区分其业务含义和计算逻辑。
| 字段 | 含义 | 考虑代金券 | 考虑币抵扣 | 考虑折扣 |
|---|---|---|---|---|
pay_amount |
折扣后应付金额 | ❌ | ❌ | ✅ |
real_amount |
实际需第三方支付金额 | ✅ | ✅ | ✅ |
pay_amount = amount * discount
real_amount = (amount - coupon_amount - ptb_amount/coin_amount) * discount
$data['amount'] (原始充值金额)
↓
代金券抵扣 → $amount = amount - coupon_amount
↓
calPayAmount() / calCoinPayAmount() → $arrPayAmount
↓
orderData() → $payData['real_amount'] + $payData['pay_amount']
GamePayService.php 第215-235行Pay::calPayAmount() / Pay::calCoinPayAmount()GamePayService.php 第583-619行pay_amount 不考虑代金券和币抵扣:仅反映折扣因素real_amount 是最终支付金额:传给第三方支付渠道的金额real_amount = 0 时直接标记支付成功:无需调用第三方支付假设:充值金额 100元,折扣 0.9,代金券 10元,专属币 20元
原始金额: 100元
代金券抵扣后: 100 - 10 = 90元
折扣后应付: 100 * 0.9 = 90元 → pay_amount
实际支付: (100 - 10 - 20) * 0.9 = 63元 → real_amount
在 PolyChannelSmsWarn.php 定时任务脚本中,当处理多个渠道的短信预警时,第一个渠道发送失败后,后续渠道不会被执行。
`php // fetchContent 方法 if(\ === false) {
// ❌ E_USER_ERROR 是致命错误,会立即终止整个 PHP 脚本执行
trigger_error("[CURL_" . curl_errno(\) . "]: " . curl_error(\), E_USER_ERROR);
} `
`php // execute 方法中的短信发送逻辑 \ = number_format(['total_advance'] - \, 2); // 返回值: "-42,299.56"(带逗号的字符串)
\ = ['name' => ['channel_name'], 'money' => number_format(\, 2)]; // ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ // 对带逗号的字符串再次 number_format 会报错 // 报错信息:A non well formed numeric value encountered `
`php // fetchContent 方法 if(\ === false) {
\ = "[CURL_" . curl_errno(\) . "]: " . curl_error(\);
curl_close(\);
// ✅ 抛出异常,可被 try-catch 捕获
throw new \RuntimeException(\);
} `
`php foreach ( \ as \ ) {
try {
// ... 原有的发送逻辑 ...
} catch (\Exception \) {
// ✅ 记录错误日志,继续执行下一个渠道
\->writeln(date('H:i:s')." [\['channel_id']] 处理异常: ".\->getMessage());
continue;
}
} `
`php \ = number_format(['total_advance'] - \, 2);
// ❌ 错误写法:对已经格式化的字符串再次格式化 // \ = ['name' => ['channel_name'], 'money' => number_format(\, 2)];
// ✅ 正确写法:直接使用已格式化的值 \ = ['name' => ['channel_name'], 'money' => ]; `
在循环处理多个任务时,永远不要使用会导致脚本终止的错误处理方式(如 E_USER_ERROR),而应该使用 ry-catch 捕获异常,确保单个失败不会影响其他任务的执行。
** umber_format() 返回的是带千分位的字符串,不是数值类型,不能直接再次格式化或参与需要数值的运算。**
最后更新:2026-07-03