应使用专用业务异常类+精准匹配处理器统一处理hyperf批量修改错误:定义batchupdateexception携带失败项等上下文,service层聚合抛出,handler中isvalid严格限定类型并返回含明细的json响应。

Hyperf 中批量修改操作的业务错误,不应依赖每个循环内手动 try/catch,而应交由框架异常处理机制统一接管——核心是「抛出语义明确的业务异常 + 注册对应异常处理器 + 配置精准匹配规则」。
定义专用业务异常类
为批量修改场景创建可识别、可分类的异常,避免混用 \Exception 或 RuntimeException:
- 在 app/Exception/BatchUpdateException.php 中定义:
<?php namespace App\Exception;
use RuntimeException;
class BatchUpdateException extends RuntimeException
{
// 可选:添加批量上下文字段,如失败条目索引、原始数据等
public array $failedItems = [];
public int $totalProcessed = 0;
}
这样后续处理器能直接提取结构化错误信息,便于前端展示明细失败项。
在 Service 层主动抛出带上下文的异常
批量逻辑中不隐藏错误,而是收集并聚合后一次性抛出,保持事务一致性(若使用 DB 事务):
- 示例:批量更新用户状态
public function batchUpdateStatus(array $updates): void
{
$failed = [];
$successCount = 0;
foreach ($updates as $index => $item) {
try {
$user = User::find($item['id']);
if (!$user) {
$failed[] = ['index' => $index, 'reason' => '用户不存在'];
continue;
}
$user->status = $item['status'] ?? 1;
$user->save();
$successCount++;
} catch (\Throwable $e) {
$failed[] = ['index' => $index, 'reason' => $e->getMessage()];
}
}
if (!empty($failed)) {
$exception = new BatchUpdateException(
sprintf('批量更新失败 %d 条,成功 %d 条', count($failed), $successCount)
);
$exception->failedItems = $failed;
$exception->totalProcessed = $successCount + count($failed);
throw $exception; // 交给全局处理器
}
}
编写精准匹配的异常处理器
新建 app/Exception/Handler/BatchUpdateExceptionHandler.php,重点实现 isValid 方法严格限定作用范围:
- 只处理 BatchUpdateException,不干扰其他异常流
- 响应体包含失败明细,方便前端做粒度反馈
<?php namespace App\Exception\Handler;
use App\Exception\BatchUpdateException;
use Hyperf\ExceptionHandler\ExceptionHandler;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Psr\Http\Message\ResponseInterface;
use Throwable;
class BatchUpdateExceptionHandler extends ExceptionHandler
{
public function handle(Throwable $throwable, ResponseInterface $response): ResponseInterface
{
$this->stopPropagation(); // 阻止传递给下一个处理器
$data = [
'code' => 400,
'message' => $throwable->getMessage(),
'failed_items' => $throwable instanceof BatchUpdateException ? $throwable->failedItems : [],
'total_processed' => $throwable instanceof BatchUpdateException ? $throwable->totalProcessed : 0,
];
return $response->withStatus(400)
->withHeader('Content-Type', 'application/json; charset=utf-8')
->withBody(new SwooleStream(json_encode($data, JSON_UNESCAPED_UNICODE)));
}
public function isValid(Throwable $throwable): bool
{
return $throwable instanceof BatchUpdateException;
}
}
注册到 HTTP 异常链并确保优先级合理
编辑 config/autoload/exceptions.php,将该处理器放在通用处理器之前(越靠前越先匹配):
return [
'handler' => [
'http' => [
App\Exception\Handler\BatchUpdateExceptionHandler::class,
App\Exception\Handler\AppExceptionHandler::class, // 通用兜底
Hyperf\HttpServer\Exception\Handler\HttpExceptionHandler::class,
],
],
];
这样当批量操作抛出 BatchUpdateException 时,会由专属处理器响应,返回含失败详情的 JSON;其他异常仍走默认流程,互不干扰。











