
本文介绍如何将一个职责混杂的 php 函数拆分为多个高内聚、低耦合的私有方法,通过提取查询构建逻辑、聚合操作和数据获取职责,显著提升代码可读性、可测试性与复用性。
本文介绍如何将一个职责混杂的 php 函数拆分为多个高内聚、低耦合的私有方法,通过提取查询构建逻辑、聚合操作和数据获取职责,显著提升代码可读性、可测试性与复用性。
原始 getTotalProductsNumber() 方法存在多个问题:职责过重(同时处理数据源初始化、条件组装、SQL 查询、类型转换)、可读性低、难以单元测试,且硬编码了表连接逻辑与字段名。重构目标是遵循单一职责原则(SRP),将不同关注点分离。
✅ 重构策略与分层设计
我们将原函数拆解为三层逻辑:
- 入口层(getTotalProductsNumber):仅负责协调流程,声明数据源与查询上下文;
- 业务逻辑层(sumOfProductQuantities):专注“求商品数量总和”这一语义化操作;
- 数据访问层(queryBuilderFirstRow):封装底层 ORM/DBM 调用,屏蔽实现细节。
public function getTotalProductsNumber(): int
{
$dataset = 'supplier_invoice_products INNER JOIN supplier_invoices AS si USING (supplier_invoice_id)';
$extras = $this->getConditionsAndOptions();
$queryBuilder = [
'dbm' => new Dbm_Supplier($dataset),
'where' => $extras['where'] ?? [],
'opt' => $extras['opt'] ?? []
];
return $this->sumOfProductQuantities($queryBuilder);
}
private function sumOfProductQuantities(array $queryBuilder): int
{
$select = 'SUM(product_quantity) AS sumTotal';
$row = $this->queryBuilderFirstRow($queryBuilder, $select);
return (int)($row['sumTotal'] ?? 0);
}
private function queryBuilderFirstRow(array $qb, string $select): array
{
// 显式校验依赖项,增强健壮性
if (!isset($qb['dbm']) || !method_exists($qb['dbm'], 'findFirstSimple')) {
throw new InvalidArgumentException('Invalid query builder: missing or invalid Dbm_Supplier instance.');
}
return $qb['dbm']->findFirstSimple($qb['where'], $select, $qb['opt']);
}
? 关键改进点说明
- 防御性编程:在 queryBuilderFirstRow 中加入参数校验,避免运行时致命错误;
- 空值安全:sumOfProductQuantities 使用 ?? 0 防止 NULL 导致 (int)null 返回 0(虽符合预期,但显式更清晰);
- 语义命名:sumOfProductQuantities 比 getTotalProductsNumber 更准确表达“聚合求和”行为,避免与计数(COUNT(*))混淆;
- 可扩展性预留:若后续需支持其他聚合(如平均值、最大值),只需新增类似 avgOfProductPrice() 方法,复用 queryBuilderFirstRow。
⚠️ 注意事项
- 确保 getConditionsAndOptions() 始终返回包含 'where' 和 'opt' 键的数组(建议为其添加 PHPDoc 类型注解或返回类型声明);
- 若项目已引入 Doctrine、Eloquent 等 ORM,应优先迁移至其 Query Builder 或 Repository 模式,而非封装原始 DBM 类;
- Dbm_Supplier 若非领域专用类,建议抽象为接口(如 InvoiceProductRepositoryInterface),便于未来替换数据源或 Mock 测试。
该重构不仅简化了主函数,更使每部分职责清晰、边界明确,为后续添加缓存、日志、权限校验等横切关注点提供了干净的扩展入口。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











