如何用策略模式与配置驱动方式优雅替代大量重复的 if 判断逻辑

梦敏大大_2552

梦敏大大_2552

2026-05-22

254人浏览

原创

如何用策略模式与配置驱动方式优雅替代大量重复的 if 判断逻辑

本文介绍一种可扩展、易维护的替代方案,通过条件映射表+动态查询构建,彻底消除数十个嵌套 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 '
'; foreach ($results as $row) { echo ""; } echo '
Patient ID Name Date of Birth Phone Number Email Sex Previous Visits
{$row['Patient_id']} {$row['Patient_name']} {$row['DOB']} {$row['Phonenum']} {$row['Email']} {$row['Sex']} Previous Visits
'; } } catch (PDOException $e) { error_log('Search query failed: ' . $e->getMessage()); echo "

Search temporarily unavailable.

"; }

⚠️ 关键注意事项

  • 绝对禁止字符串拼接用户输入:所有值必须通过 PDO 参数绑定(:param)传入,杜绝 SQL 注入。
  • 字段名白名单校验:$option 和 $newoption 必须严格限定在 $fields 键中,防止恶意字段注入。
  • 空值/类型防御:每个字段的 validator 函数应独立校验,避免 !empty() 对数字 0 或字符串 '0' 的误判。
  • 扩展性保障:新增字段只需在配置中追加一项,无需修改主逻辑;组合逻辑由通用引擎自动覆盖。
  • 性能提示:对高频查询字段(如 Email, Patient_id)确保数据库已建立索引。

这种设计将原本 20+ 个脆弱的 if 分支压缩为一份声明式配置与一段健壮的通用执行器——它不仅是“更少代码”,更是可测试、可审计、可演进的搜索架构起点。

驱动精灵
驱动精灵

驱动精灵基于驱动之家十余年的专业数据积累,驱动支持度高,已经为数亿用户解决了各种电脑驱动问题、系统故障,是目前有效的驱动软件,有需要的小伙伴快来保存下载体验吧!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
php文件怎么打开
php文件怎么打开

打开php文件步骤:1、选择文本编辑器;2、在选择的文本编辑器中,创建一个新的文件,并将其保存为.php文件;3、在创建的PHP文件中,编写PHP代码;4、要在本地计算机上运行PHP文件,需要设置一个服务器环境;5、安装服务器环境后,需要将PHP文件放入服务器目录中;6、一旦将PHP文件放入服务器目录中,就可以通过浏览器来运行它。

2023.09.01

10244

6

php怎么取出数组的前几个元素
php怎么取出数组的前几个元素

取出php数组的前几个元素的方法有使用array_slice()函数、使用array_splice()函数、使用循环遍历、使用array_slice()函数和array_values()函数等。本专题为大家提供php数组相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.11

6041

5

php反序列化失败怎么办
php反序列化失败怎么办

php反序列化失败的解决办法检查序列化数据。检查类定义、检查错误日志、更新PHP版本和应用安全措施等。本专题为大家提供php反序列化相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.11

2095

5

php怎么连接mssql数据库
php怎么连接mssql数据库

连接方法:1、通过mssql_系列函数;2、通过sqlsrv_系列函数;3、通过odbc方式连接;4、通过PDO方式;5、通过COM方式连接。想了解php怎么连接mssql数据库的详细内容,可以访问下面的文章。

2023.10.23

3808

4

php连接mssql数据库的方法
php连接mssql数据库的方法

php连接mssql数据库的方法有使用PHP的MSSQL扩展、使用PDO等。想了解更多php连接mssql数据库相关内容,可以阅读本专题下面的文章。

2023.10.23

4514

6

html怎么上传
html怎么上传

html通过使用HTML表单、JavaScript和PHP上传。更多关于html的问题详细请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.03

3531

9

PHP出现乱码怎么解决
PHP出现乱码怎么解决

PHP出现乱码可以通过修改PHP文件头部的字符编码设置、检查PHP文件的编码格式、检查数据库连接设置和检查HTML页面的字符编码设置来解决。更多关于php乱码的问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.09

5037

8

php文件怎么在手机上打开
php文件怎么在手机上打开

php文件在手机上打开需要在手机上搭建一个能够运行php的服务器环境,并将php文件上传到服务器上。再在手机上的浏览器中输入服务器的IP地址或域名,加上php文件的路径,即可打开php文件并查看其内容。更多关于php相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.13

3942

8

sprintf函数用法详解
sprintf函数用法详解

sprintf函数的用法:1、格式化字符串;2、指定输出宽度和精度;3、返回值。更多关于sprintf函数用法详解的内容,大家可以阅读下面的文章。

2023.11.27

11922

4

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.6万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.4万人学习