
本文介绍一种可扩展、易维护的替代方案,通过条件映射表+动态查询构建,彻底消除数十个嵌套 if 的硬编码逻辑,提升搜索功能的可读性与可维护性。
本文介绍一种可扩展、易维护的替代方案,通过条件映射表+动态查询构建,彻底消除数十个嵌套 if 的硬编码逻辑,提升搜索功能的可读性与可维护性。
在构建数据库搜索工具时,面对“主字段 + 扩展字段”组合(如 Name + Email、Name + Age、ID + Sex 等)所引发的指数级 if 分支,硬编码判断不仅难以维护,更易引入 SQL 拼接漏洞与逻辑遗漏。真正的 SMART 方式不是优化 if 层级,而是抽象匹配规则、解耦条件与行为、按需组装查询。
✅ 推荐方案:配置驱动 + 动态查询构建
核心思想是将“字段组合 → 查询片段 → 参数校验 → 结果渲染”映射为结构化配置,并通过统一调度器执行,避免任何重复分支。
1. 定义字段元数据与条件映射表
首先建立清晰的字段规范(含 SQL 片段、校验规则、占位符):
// config/search_fields.php
return [
'Name' => [
'type' => 'like',
'column' => 'patients.Patient_name',
'placeholder' => '%{value}%',
'validator' => fn($v) => !empty(trim($v)),
],
'Email' => [
'type' => 'exact',
'column' => 'patients.Email',
'placeholder' => '{value}',
'validator' => fn($v) => filter_var($v, FILTER_VALIDATE_EMAIL),
],
'Age' => [
'type' => 'range_gt',
'column' => "TIMESTAMPDIFF(YEAR, patients.DOB, CURDATE())",
'placeholder' => '{value}',
'validator' => fn($v) => is_numeric($v) && $v > 0,
],
'ID' => [
'type' => 'exact',
'column' => 'patients.Patient_id',
'placeholder' => '{value}',
'validator' => fn($v) => is_numeric($v),
],
// 其他字段...
];
2. 构建动态查询生成器
根据用户选择的 $option(主字段)和 $newoption(扩展字段),安全拼接 WHERE 子句:
<?php $fields = require 'config/search_fields.php';
// 基础查询骨架(含 JOIN 和 Doctor_ID 过滤)
$sql = "SELECT patients.Patient_id, patients.Patient_name, patients.DOB,
patients.Phonenum, patients.Email, MSR.Sex
FROM patients
INNER JOIN MSR ON patients.Patient_id = MSR.NDSnum
WHERE Doctor_ID = :doctor_id";
$params = [':doctor_id' => $usersid];
$conditions = [];
// 主字段条件
if (isset($fields[$option]) && $fields[$option]['validator']($entry)) {
$fieldConf = $fields[$option];
$placeholder = str_replace('{value}', $entry, $fieldConf['placeholder']);
switch ($fieldConf['type']) {
case 'like':
$conditions[] = "{$fieldConf['column']} LIKE :name";
$params[':name'] = $placeholder;
break;
case 'exact':
$conditions[] = "{$fieldConf['column']} = :value";
$params[':value'] = $entry;
break;
case 'range_gt':
$conditions[] = "{$fieldConf['column']} > :age";
$params[':age'] = (int)$entry;
break;
}
}
// 扩展字段条件(仅当 newoption 有效且值非空)
if (!empty($newoption) && isset($fields[$newoption])) {
$newVal = ${'new' . ucfirst($newoption)} ?? null; // 如 $newEmail, $newAge
if ($fields[$newoption]['validator']($newVal)) {
$newConf = $fields[$newoption];
$placeholder = str_replace('{value}', $newVal, $newConf['placeholder']);
switch ($newConf['type']) {
case 'like':
$conditions[] = "{$newConf['column']} LIKE :new_name";
$params[':new_name'] = $placeholder;
break;
case 'exact':
$conditions[] = "{$newConf['column']} = :new_value";
$params[':new_value'] = $newVal;
break;
case 'range_gt':
$conditions[] = "{$newConf['column']} > :new_age";
$params[':new_age'] = (int)$newVal;
break;
}
}
}
// 组装完整 WHERE
if (!empty($conditions)) {
$sql .= ' AND (' . implode(" $and_or ", $conditions) . ')';
}
$sql .= ' ORDER BY patients.Patient_id';
?>
3. 统一执行与渲染(无重复 HTML)
try {
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (empty($results)) {
echo "<p>No patient exists with this information.</p>";
} else {
echo '
| Patient ID | Name | Date of Birth | Phone Number | Sex | Previous Visits | |
|---|---|---|---|---|---|---|
| {$row['Patient_id']} | {$row['Patient_name']} | {$row['DOB']} | {$row['Phonenum']} | {$row['Email']} | {$row['Sex']} | Previous Visits |
Search temporarily unavailable.
"; }⚠️ 关键注意事项
- 绝对禁止字符串拼接用户输入:所有值必须通过 PDO 参数绑定(:param)传入,杜绝 SQL 注入。
- 字段名白名单校验:$option 和 $newoption 必须严格限定在 $fields 键中,防止恶意字段注入。
- 空值/类型防御:每个字段的 validator 函数应独立校验,避免 !empty() 对数字 0 或字符串 '0' 的误判。
- 扩展性保障:新增字段只需在配置中追加一项,无需修改主逻辑;组合逻辑由通用引擎自动覆盖。
- 性能提示:对高频查询字段(如 Email, Patient_id)确保数据库已建立索引。
这种设计将原本 20+ 个脆弱的 if 分支压缩为一份声明式配置与一段健壮的通用执行器——它不仅是“更少代码”,更是可测试、可审计、可演进的搜索架构起点。










