嵌套foreach代码重构咨询:拆分函数与参数传递疑问
拆分发票价格计算PHP代码的子函数方案
我编写了一段用于计算发票产品价格的PHP代码,包含双层foreach循环。当产品数量为负值时代表该产品是退货,需从总价中扣减对应金额。目前这段代码因大量计算逻辑集中在循环内,显得冗余杂乱,希望将其拆分为多个子函数,但不清楚子函数应该传递哪些参数,原代码如下:
$dataset = 'supplier_invoices'; $SupplierInvoice = new Dbm_Supplier($dataset); $totalValoare = 0; $costAdaos = 0; $totalTva_neex = 0; $totalVal_cu_tva = 0; $totalValoareCantitateNegativaProduseFacturate = 0; $costAdaosCantitateNegativaProduseFacturate = 0; $totalTva_neexCantitateNegativaProduseFacturate = 0; $totalVal_cu_tvaCantitateNegativaProduseFacturate = 0; $totalValoarePozitivaProduseFacturate = 0; $costAdaosPozitivaProduseFacturate = 0; $totalTva_neexPozitivaProduseFacturate = 0; $totalVal_cu_tvaPozitivaProduseFacturate = 0; $totalValoareProduseFurnizor = 0; $costAdaosProduseFurnizor = 0; $totalTva_neexProduseFurnizor = 0; $totalVal_cu_tvaProduseFurnizor = 0; $totalValoareProduseFurnizorReturnate = 0; $costAdaosProduseFurnizorReturnate = 0; $totalTva_neexProduseFurnizorReturnate = 0; $totalVal_cu_tvaProduseFurnizorReturnate = 0; foreach ($invoices as $invoice) { $data = $SupplierInvoice->findFirst(array('supplier_invoice_id'=>$invoice['supplier_invoice_id'])); $data = $data['results']; $invoiceCalculus = new InvoiceSupplierCalculus($data['supplier_invoice_date'], $data['currency_rate']); $products = $SupplierInvoice->getProductsForInvoice($invoice['supplier_invoice_id']); foreach ($products as $product) { $calculus = $invoiceCalculus->getCalculus($product); $valoare = $calculus['default_currency_value']; $adaos_com = $calculus['adaos_com']; $tva_neex = $calculus['tva_neex']; $val_cu_tva = $calculus['val_cu_tva']; $totalValoare += $valoare; $costAdaos += $adaos_com; $totalTva_neex += $tva_neex; $totalVal_cu_tva += $val_cu_tva; $totalVal_cu_tva = number_format($totalVal_cu_tva,2,'.',''); if($product['invoice_quantity'] < 0) { $totalValoareCantitateNegativaProduseFacturate += -1 * abs($valoare); $costAdaosCantitateNegativaProduseFacturate += -1 * abs($adaos_com); $totalTva_neexCantitateNegativaProduseFacturate += -1 * abs($tva_neex); $totalVal_cu_tvaCantitateNegativaProduseFacturate += -1 * abs($val_cu_tva); $totalVal_cu_tvaCantitateNegativaProduseFacturate = number_format($totalVal_cu_tvaCantitateNegativaProduseFacturate,2,'.',''); } else { $totalValoarePozitivaProduseFacturate += abs($valoare); $costAdaosPozitivaProduseFacturate += abs($adaos_com); $totalTva_neexPozitivaProduseFacturate += abs($tva_neex); $totalVal_cu_tvaPozitivaProduseFacturate += abs($val_cu_tva); $totalVal_cu_tvaPozitivaProduseFacturate = number_format($totalVal_cu_tvaPozitivaProduseFacturate,2,'.',''); } if($product['product_quantity'] < 0) { $totalValoareProduseFurnizorReturnate += $valoare; $costAdaosProduseFurnizorReturnate += $adaos_com; $totalTva_neexProduseFurnizorReturnate += $tva_neex; $totalVal_cu_tvaProduseFurnizorReturnate += $val_cu_tva; $totalVal_cu_tvaProduseFurnizorReturnate = number_format($totalVal_cu_tvaProduseFurnizorReturnate,2,'.',''); } else { $totalValoareProduseFurnizor += $valoare; $costAdaosProduseFurnizor += $adaos_com; $totalTva_neexProduseFurnizor += $tva_neex; $totalVal_cu_tvaProduseFurnizor += $val_cu_tva; $totalVal_cu_tvaProduseFurnizor = number_format($totalVal_cu_tvaProduseFurnizor,2,'.',''); } } }
拆分思路与实现
1. 封装统计数据结构
把分散的统计变量整合成嵌套数组,避免大量独立变量,让参数传递更清晰:
function initializeInvoiceStats() { return [ 'total' => [ 'valoare' => 0, 'adaos_com' => 0, 'tva_neex' => 0, 'val_cu_tva' => 0, ], 'invoice_negative' => [ 'valoare' => 0, 'adaos_com' => 0, 'tva_neex' => 0, 'val_cu_tva' => 0, ], 'invoice_positive' => [ 'valoare' => 0, 'adaos_com' => 0, 'tva_neex' => 0, 'val_cu_tva' => 0, ], 'supplier_normal' => [ 'valoare' => 0, 'adaos_com' => 0, 'tva_neex' => 0, 'val_cu_tva' => 0, ], 'supplier_returned' => [ 'valoare' => 0, 'adaos_com' => 0, 'tva_neex' => 0, 'val_cu_tva' => 0, ], ]; }
2. 拆分核心子函数
所有子函数通过引用传递统计数组,避免数组拷贝,同时直接修改统计值。
处理单张发票
参数:单条发票数据、Dbm_Supplier实例、统计数组引用
function processSingleInvoice($invoice, $supplierInvoice, &$stats) { $data = $supplierInvoice->findFirst(['supplier_invoice_id' => $invoice['supplier_invoice_id']])['results']; $invoiceCalculus = new InvoiceSupplierCalculus($data['supplier_invoice_date'], $data['currency_rate']); $products = $supplierInvoice->getProductsForInvoice($invoice['supplier_invoice_id']); foreach ($products as $product) { processSingleProduct($product, $invoiceCalculus, $stats); } }
处理单个产品
参数:单条产品数据、InvoiceSupplierCalculus实例、统计数组引用
function processSingleProduct($product, $invoiceCalculus, &$stats) { $calculus = $invoiceCalculus->getCalculus($product); $calcValues = [ 'valoare' => $calculus['default_currency_value'], 'adaos_com' => $calculus['adaos_com'], 'tva_neex' => $calculus['tva_neex'], 'val_cu_tva' => $calculus['val_cu_tva'], ]; // 更新总统计 updateStats($stats['total'], $calcValues); // 按invoice_quantity分类更新 if ($product['invoice_quantity'] < 0) { updateNegativeInvoiceStats($stats['invoice_negative'], $calcValues); } else { updatePositiveInvoiceStats($stats['invoice_positive'], $calcValues); } // 按product_quantity分类更新(供应商产品/退货) if ($product['product_quantity'] < 0) { updateStats($stats['supplier_returned'], $calcValues); } else { updateStats($stats['supplier_normal'], $calcValues); } }
通用统计更新函数
参数:目标统计数组引用、当前产品的计算值数组
function updateStats(&$targetStats, $calcValues) { $targetStats['valoare'] += $calcValues['valoare']; $targetStats['adaos_com'] += $calcValues['adaos_com']; $targetStats['tva_neex'] += $calcValues['tva_neex']; $targetStats['val_cu_tva'] = number_format($targetStats['val_cu_tva'] + $calcValues['val_cu_tva'], 2, '.', ''); } // 针对负数量发票的特殊处理 function updateNegativeInvoiceStats(&$targetStats, $calcValues) { $targetStats['valoare'] += -1 * abs($calcValues['valoare']); $targetStats['adaos_com'] += -1 * abs($calcValues['adaos_com']); $targetStats['tva_neex'] += -1 * abs($calcValues['tva_neex']); $targetStats['val_cu_tva'] = number_format($targetStats['val_cu_tva'] + (-1 * abs($calcValues['val_cu_tva'])), 2, '.', ''); } // 针对正数量发票的特殊处理 function updatePositiveInvoiceStats(&$targetStats, $calcValues) { $targetStats['valoare'] += abs($calcValues['valoare']); $targetStats['adaos_com'] += abs($calcValues['adaos_com']); $targetStats['tva_neex'] += abs($calcValues['tva_neex']); $targetStats['val_cu_tva'] = number_format($targetStats['val_cu_tva'] + abs($calcValues['val_cu_tva']), 2, '.', ''); }
3. 简化主流程
$dataset = 'supplier_invoices'; $SupplierInvoice = new Dbm_Supplier($dataset); $stats = initializeInvoiceStats(); foreach ($invoices as $invoice) { processSingleInvoice($invoice, $SupplierInvoice, $stats); } // 后续可直接使用$stats数组中的统计结果
参数传递说明
- 统计数组:始终用引用传递,确保子函数能直接修改原数组,避免性能损耗。
- 实例对象:传递
Dbm_Supplier和InvoiceSupplierCalculus实例,因为子函数需要调用它们的方法查询数据、计算金额。 - 业务数据:传递单条发票/产品数据,是计算的基础输入。
- 计算值数组:将产品的四个核心计算值封装成数组传递,减少单个参数的数量,提高可读性。
内容的提问来源于stack exchange,提问作者user3848412
相关产品推荐
相关产品推荐

