错误码必须集中用类常量定义,不可用define();msg需动态翻译,不可写死;异常抛出和响应构造时须绑定 errorcode,避免冲突与调试盲区。

错误码不能靠零散的 define() 或类常量硬编码散落在各处,否则查不到、改不动、IDE 跳不了 —— 真正可用的错误码必须集中管理、可查可搜、与业务异常强绑定。
错误码该定义成类常量还是 define()?
用类常量,别用 define()。ThinkPHP5 的运行时环境不保证所有 define() 在全局任意位置都已加载(比如某些 CLI 场景或异步任务中),而类常量只要类被自动加载就一定可用。更重要的是,IDE 能跳转、能提示、能批量重命名;define() 定义的常量在 PHPStorm 里基本是“黑盒”,搜 USER_NOT_FOUND 找不到定义位置。
推荐写法:
namespace app\common;
class ErrorCode
{
const USER_NOT_FOUND = 1001;
const INVALID_TOKEN = 2002;
const PARAM_ERROR = 4000;
}
调用时直接写 ErrorCode::USER_NOT_FOUND,语义清晰,类型安全,无加载顺序风险。
为什么不能把错误信息(msg)也写死在常量定义里?
因为错误详情往往依赖上下文:比如“手机号已被注册”和“邮箱已被注册”都属于 PARAM_ERROR,但 msg 必须动态拼接。若把完整提示塞进常量或静态数组,会导致:
- 无法支持多语言切换(
$lang参数加不进去) - 违反单一职责:错误码标识问题类型,msg 是呈现层逻辑
- 后续加校验规则时,得反复改常量文件,容易漏掉某处调用
正确做法是只在类里维护码值映射表,用独立方法做翻译:
public static function msg(int $code, string $lang = 'zh-cn'): string
{
$map = [
self::USER_NOT_FOUND => ['zh-cn' => '用户不存在', 'en-us' => 'User not found'],
self::INVALID_TOKEN => ['zh-cn' => '登录已过期,请重新登录', 'en-us' => 'Login expired, please log in again'],
];
return $map[$code][$lang] ?? 'Unknown error';
}
错误码在哪抛、在哪用才真正生效?
必须出现在两个关键节点:
- 抛异常时:用
throw new BusinessException(ErrorCode::USER_NOT_FOUND),而不是throw new Exception('用户不存在') - 响应构造时:在控制器基类的
fail()方法或全局异常处理器render()中,从异常对象里取$e->getCode(),再调ErrorCode::msg($code)填入 JSON 的msg字段
ThinkPHP5 的 JsonResponse 不会自动读取异常码对应的中文描述 —— 它只认 $e->getMessage()。如果你没在 render() 里手动查 ErrorCode,前端看到的永远是“用户不存在”这种写死字符串,或者更糟:空 msg。
常见踩坑点:错误码重复、覆盖、无法调试
最容易被忽略的是错误码冲突和调试盲区:
- 多人协作时,没人检查新码是否已存在,结果
const ORDER_PAID = 3001和别人写的const REFUND_FAILED = 3001冲突了 - 线上出错只返回
code: 4000,但开发环境没配好ErrorCode::msg(),日志里看不到具体含义 - 异常处理器里没做
instanceof BusinessException判断,导致框架原生异常也被当成业务码去查ErrorCode,报Undefined index
建议上线前跑一遍 array_unique() 检查类中所有 const 值是否唯一,并在 msg() 方法开头加个兜底:if (!isset(self::$map[$code])) { throw new \InvalidArgumentException("Unknown error code: {$code}"); } —— 宁可崩得明确,也不要静默错。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











