
本文介绍如何将臃肿的 exportFile() 函数按单一职责原则拆分为高内聚、低耦合的独立函数,涵盖文件操作、数据获取、平台专属导出逻辑及 CSV 行构建等模块,提升可读性、可测试性与可维护性。
本文介绍如何将臃肿的 `exportfile()` 函数按单一职责原则拆分为高内聚、低耦合的独立函数,涵盖文件操作、数据获取、平台专属导出逻辑及 csv 行构建等模块,提升可读性、可测试性与可维护性。
在 PHP 开发中,一个超过 50 行、混合数据库查询、文件 I/O、多平台逻辑和格式化处理的函数(如原始 exportFile)不仅难以调试和单元测试,还严重违反了 单一职责原则(SRP) 和 开闭原则(OCP)。以下是经过工程化重构后的专业实践方案:
✅ 核心拆分策略
我们将原函数解耦为以下职责清晰的函数:
- openExportFile():专注文件打开与错误处理;
- fetchExportData():封装数据库连接与查询,返回标准化数组;
- getPlatformHeaders(string $platform):返回各平台专用 CSV 表头;
- buildPlatformRow(array $row, string $platform):将原始数据行映射为对应平台的 CSV 字段数组;
- writeCsvContent(resource $file, array $data, string $platform):统一执行表头写入 + 循环写入逻辑。
✅ 重构后完整代码示例
function openExportFile(string $fileName): resource
{
$filePath = DOWNLOAD_FILE_PATH . $fileName;
$file = fopen($filePath, 'wb');
if (!$file) {
throw new RuntimeException(json_encode([
'status' => 'error',
'errMessage' => "Failed to open file: {$filePath}"
]));
}
return $file;
}
function fetchExportData(): array
{
$db = new MysqliDb(TEST_DB_HOSTNAME, TEST_DB_USERNAME, TEST_DB_PASSWORD, TEST_DB_DATABASE);
return $db->rawQuery("SELECT * FROM database");
}
function getPlatformHeaders(string $platform): array
{
return match ($platform) {
'magento' => ['SKU', 'Name', 'Price', 'Category'],
'catch' => ['ProductID', 'Title', 'RRP', 'Department'],
'amazon' => ['asin', 'title', 'list_price', 'brand'],
default => throw new InvalidArgumentException("Unsupported platform: {$platform}")
};
}
function buildPlatformRow(array $row, string $platform): array
{
return match ($platform) {
'magento' => [
$row['sku'] ?? '',
$row['product_name'] ?? '',
(float)($row['price'] ?? 0),
$row['category_path'] ?? ''
],
'catch' => [
(int)($row['id'] ?? 0),
$row['name'] ?? '',
round((float)($row['rrp'] ?? 0), 2),
$row['department'] ?? ''
],
'amazon' => [
$row['asin'] ?? '',
$row['item_name'] ?? '',
number_format((float)($row['msrp'] ?? 0), 2),
$row['brand_name'] ?? ''
],
default => throw new InvalidArgumentException("Unsupported platform: {$platform}")
};
}
function writeCsvContent(resource $file, array $data, string $platform): void
{
fputcsv($file, getPlatformHeaders($platform));
foreach ($data as $row) {
fputcsv($file, buildPlatformRow($row, $platform));
}
}
// 主入口函数 —— 仅协调流程,无业务逻辑
function exportFile(string $fileName, string $platform, ?string $option = null): void
{
$file = openExportFile($fileName);
try {
$data = fetchExportData();
writeCsvContent($file, $data, $platform);
fclose($file);
} catch (Exception $e) {
fclose($file);
throw $e;
}
}⚠️ 关键注意事项
- 避免全局变量与硬编码:所有配置(如数据库凭证、路径)应通过依赖注入或配置管理器传入,而非直接使用常量。
- 异常优于 die():使用 throw 替代 die(),便于上层捕获并统一处理错误响应(如 API 返回 JSON 错误)。
- 类型声明强化健壮性:PHP 7.4+ 强烈建议启用严格模式并添加 string, array, resource 等类型提示。
- 扩展性设计:新增平台(如 shopify)只需扩展 getPlatformHeaders() 和 buildPlatformRow() 的 match 分支,无需修改主流程。
- 后续增强方向:可进一步抽象为策略模式(ExportStrategyInterface),配合工厂类动态实例化,实现真正可插拔架构。
通过以上拆分,每个函数长度控制在 15 行以内,职责单一、命名自解释、易于单独单元测试(例如可 mock buildPlatformRow 验证字段映射逻辑),显著提升团队协作效率与长期可维护性。



















