
本文介绍一种可维护、可扩展的替代方案,用配置驱动的条件映射与动态 sql 构建机制,彻底取代数百行重复的 if-else 组合判断,显著提升搜索逻辑的清晰度与可维护性。
本文介绍一种可维护、可扩展的替代方案,用配置驱动的条件映射与动态 sql 构建机制,彻底取代数百行重复的 if-else 组合判断,显著提升搜索逻辑的清晰度与可维护性。
在构建多条件组合搜索功能时(如“姓名 + 邮箱”“姓名 + 年龄 >”“ID + 性别”等),若采用硬编码的 if ($option == 'Name' && $newoption == 'Email') 方式逐条枚举所有组合,不仅代码量爆炸(20+ 属性 → 可能超 400 种两两组合),更会导致逻辑耦合严重、难以新增字段、极易引入 SQL 注入与空值漏洞。
真正的 SMART 方式是:解耦「条件识别」与「查询生成」,用数据结构代替分支语句。
✅ 推荐方案:条件映射表 + 动态 SQL 构建器
核心思想是将每种属性组合的处理逻辑抽象为可配置的规则,通过数组映射快速定位,并利用参数化查询安全拼接 WHERE 子句。
1. 定义属性元数据与条件映射
// config/search_rules.php
return [
// 主条件字段 => [子条件字段 => 查询片段配置]
'Name' => [
'Email' => [
'where' => "patients.Email = :newEmail",
'params' => ['newEmail' => $newEmail],
'message' => '姓名+邮箱'
],
'Age' => [
'where' => "TIMESTAMPDIFF(YEAR, patients.DOB, CURDATE()) > :newAge",
'params' => ['newAge' => $newAge],
'message' => '姓名+年龄大于'
],
'Sex' => [
'where' => "MSR.Sex = :newSex",
'params' => ['newSex' => $newSex],
'message' => '姓名+性别',
'join' => "JOIN MSR ON patients.Patient_id = MSR.NDSnum"
]
],
'ID' => [
'Email' => [
'where' => "patients.Email = :newEmail",
'params' => ['newEmail' => $newEmail],
'message' => '患者ID+邮箱'
]
],
// 可按需持续追加,无需改主逻辑
];
2. 统一查询执行引擎(安全、简洁)
// search_handler.php
$rules = require 'config/search_rules.php';
// 检查主选项与子选项是否合法且值非空
if (isset($rules[$option][$newoption])
&& !empty(${'new' . ucfirst($newoption)})) {
$rule = $rules[$option][$newoption];
$baseSql = "SELECT patients.Patient_id, patients.Patient_name, patients.DOB,
patients.Phonenum, patients.Email, MSR.Sex
FROM patients
{$rule['join'] ?? ''}
WHERE Doctor_ID = :usersid";
// 主条件(如 Name LIKE)
$mainCondition = match($option) {
'Name' => "patients.Patient_name LIKE :entry",
'ID' => "patients.Patient_id = :entry",
'Email'=> "patients.Email = :entry",
default=> throw new InvalidArgumentException("不支持的主选项: $option")
};
$sql = "$baseSql AND $mainCondition $and_or {$rule['where']} ORDER BY patients.Patient_id";
$stmt = $pdo->prepare($sql);
$stmt->bindValue(':usersid', $usersid, PDO::PARAM_INT);
$stmt->bindValue(':entry', "%$entry%", PDO::PARAM_STR);
// 绑定子条件参数(自动处理类型)
foreach ($rule['params'] as $param => $value) {
$type = is_numeric($value) ? PDO::PARAM_INT : PDO::PARAM_STR;
$stmt->bindValue(":$param", $value, $type);
}
$stmt->execute();
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (!empty($results)) {
// 渲染表格(复用同一模板,避免重复 HTML)
include 'templates/search_results.php';
} else {
echo "未找到匹配的患者记录({$rule['message']})";
}
} else {
echo "无效的搜索组合或缺少输入值";
}
3. 关键优势与注意事项
- ✅ 零重复判断:不再写 if ($option=='X' && $newoption=='Y'),所有组合由配置驱动;
- ✅ SQL 注入免疫:全程使用 PDO::prepare() + 命名占位符,杜绝字符串拼接;
- ✅ 类型安全:根据值自动推断绑定类型(数字用 PARAM_INT,字符串用 PARAM_STR);
- ✅ 易扩展:新增字段只需在配置数组中添加一行,无需修改业务逻辑;
- ✅ 可测试性强:规则数组可单独单元测试,SQL 生成逻辑可 mock 验证;
⚠️ 重要提醒:
- 前端传入的 $and_or 必须严格校验(仅允许 'AND' 或 'OR'),防止 SQL 注入;
- 所有用户输入(如 $entry, $newEmail)必须经 trim() 和空值检查后再参与逻辑;
- 多表 JOIN 场景下,注意字段前缀统一(如 patients.Email 而非裸 Email);
- 若需支持三条件及以上搜索,可将规则升级为树状结构或引入表达式解析器(如 symfony/expression-language)。
通过将“什么条件触发什么查询”从代码中抽离为声明式配置,你不仅解决了当前的 if 泛滥问题,更为未来搜索能力的演进(如模糊匹配、范围筛选、全文索引)铺平了道路——这才是真正可持续的 SMART 实践。










