自定义错误类必须继承axyerrorslogic或runtime,禁用直接extendsexception;需声明psr-4自动加载、覆写$defaultmessage、构造函数注入上下文参数,并在真实vendor环境验证。

自定义错误处理类必须继承 AxyErrorsLogic 或 AxyErrorsRuntime
直接 new Exception() 或 extends Exception 写法在 Composer 包中会破坏异常层次结构,导致调用方无法按业务维度统一捕获。AxyErrors 提供的基类已内置默认消息模板、堆栈截断和分类标识,这是包可维护性的基础。
常见错误是把自定义异常写成“裸类”:
class UploadFailedException extends Exception {} // ❌ 无默认消息、无分类、堆栈全量暴露
正确做法是明确归属:
-
AxyErrorsLogic用于参数错误、状态非法、业务规则违反等可预判问题 -
AxyErrorsRuntime用于文件不可读、网络超时、扩展未加载等运行时意外 - 所有子类应覆写
$defaultMessage属性,避免调用方每次都要传重复字符串
composer.json 中必须声明 autoload 并执行 dump-autoload
即使类文件存在,若未在 autoload 段注册,Composer 安装后其他项目 require 你的包时,class not found 会静默失败——因为自动加载器根本不知道这个类在哪。
PSR-4 映射要精确到命名空间根:
"autoload": {
"psr-4": {
"MyOrg\Upload\": "src/"
}
}
注意两点:
- 路径
"src/"必须真实存在且含Upload/子目录,否则映射失效 - 修改后必须手动运行
composer dump-autoload,仅composer install不会触发重生成 - 若类在
src/Exceptions/下,命名空间就得是MyOrg\Upload\Exceptions\,不能靠自动补全猜
抛出异常时避免硬编码消息,优先用 __construct() 参数注入上下文
包的使用者需要区分“什么错了”和“为什么错”。把错误原因塞进消息字符串里,会导致日志解析困难、i18n 支持断裂。
推荐模式是构造函数接收关键变量,内部拼接:
class FileSizeExceededException extends AxyErrorsRuntime
{
protected $defaultMessage = 'File size exceeds limit: {max} bytes, got {actual}.';
public function __construct(int $max, int $actual)
{
parent::__construct(['max' => $max, 'actual' => $actual]);
}
}
这样既保留结构化数据,又支持后期替换语言模板。别这么做:
throw new FileSizeExceededException('File too big: 2MB limit, got 5MB'); // ❌ 消息不可拆解
测试异常路径必须覆盖 vendor/autoload.php 加载后的实际环境
本地 phpunit 直接运行测试文件时,不会走 Composer 自动加载逻辑,容易漏掉 PSR-4 路径错误或类名大小写不一致问题。
真实集成场景下,异常类必须能被下游项目通过 require 'vendor/autoload.php' 正常加载并抛出。验证方法只有两种:
- 在另一个空项目中
composer require myorg/upload,然后写个最小脚本new MyOrgUploadExceptionsFileSizeExceededException(1024, 2048); - CI 流水线中禁用
--no-dev,确保测试依赖和 autoloader 全链路生效
最容易被忽略的是 Windows 和 macOS 文件系统对大小写的宽容性——开发时类名写成 filesizeexceededexception.php 可能不报错,但部署到 Linux 就直接 class not found。











