PHP 怎么业务规则动态

wen PHP项目 1

本文目录导读:

PHP 怎么业务规则动态

  1. 方案一:配置驱动(适合简单规则)
  2. 方案二:表达式语言(适合中等复杂规则)
  3. 方案三:规则引擎库(适合复杂业务流转)
  4. 方案四:DSL(领域特定语言)+ 脚本执行(最灵活,类似低代码)
  5. 🛡️ 安全建议(重要!)
  6. 总结建议

在 PHP 中实现业务规则的动态化(即在运行时根据条件改变逻辑,而非硬编码)有多种方案,具体取决于你需要的复杂度性能维护性

以下是由简到繁的四种主流方案,附带代码示例和适用场景:


配置驱动(适合简单规则)

原理:将规则中的“变量”和“阈值”抽离到数据库或配置文件中,代码逻辑不变,但参数可动态调整。

示例:动态调整“满减”门槛。

// 数据库表:promotion_rules (id, rule_key, rule_value)
// 读取配置
$config = DB::table('promotion_rules')->where('rule_key', 'full_reduction')->first();
$threshold = $config->threshold; // 例如满100
$discount = $config->discount;   // 例如减20
// 业务逻辑
if ($cart_total >= $threshold) {
    $final_price = $cart_total - $discount;
}
// 修改数据库中的 threshold 值,下次请求立即生效,无需改代码

适用场景:优惠券门槛、运费计算、会员等级积分倍率等参数经常变动的场景。 优点:实现最简单,运行速度快。 缺点:只能动态改数字/字符串,无法动态改逻辑结构(如“且/或”的条件组合)。


表达式语言(适合中等复杂规则)

原理:使用 eval() 或者第三方库(如 Symfony ExpressionLanguage)直接解析用户输入的公式或逻辑表达式。

示例:使用 Symfony ExpressionLanguage(推荐,比 eval() 安全)。

use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
$language = new ExpressionLanguage();
// 规则从数据库读取, "user.age >= 18 and user.level in ['gold', 'vip']"
$rule_expression = $row->rule_expression;
// 传入上下文数据
$data = ['user' => ['age' => 25, 'level' => 'gold']];
// 动态执行
$result = $language->evaluate($rule_expression, $data);
if ($result) {
    // 执行对应动作(动作也可由配置文件映射)
    $action = $row->action; // send_gift
    executeAction($action);
}

适用场景:需要非技术人员(运营人员)在后台配置复杂的“条件组合”逻辑。 优点:支持 and, or, , in 等运算符,逻辑灵活性高。 缺点:不能执行复杂循环和数据库查询;需注意防止公式注入(只允许白名单函数)。


规则引擎库(适合复杂业务流转)

原理:引入成熟的规则引擎(如 RulerZ),支持对象访问、权限校验,以及更复杂的规则组合。

示例:使用 Hoa\Ruler(或 RulerZ)。

// 定义规则(通常来自数据库)
$rule = 'customer.is_active and (customer.orders_count > 5 or customer.total_spent > 1000)';
// 使用规则引擎解析
$ruler = new \Hoa\Ruler\Ruler();
$myModel = new \Hoa\Ruler\Context(); // 将数据放入Context
// 执行
if ($ruler->assert($rule, $myModel)) {
    // 执行优惠逻辑
}

适用场景:电商风控、CRM 客户分群、营销自动化中的多条件匹配。 优点:规则复用性强,支持嵌套,不再写 if/else 地狱。 缺点:学习成本稍高,性能开销较大,不适用于高并发核心路径。


DSL(领域特定语言)+ 脚本执行(最灵活,类似低代码)

原理:定义一个简单的“伪代码”或 JSON 结构,将业务逻辑拆分为“节点”(条件节点、动作节点),系统解析并执行。

示例:基于 JSON 的规则链(类似流程图)。

$rule = json_decode('{
    "type": "if",
    "condition": {
        "field": "product.stock",
        "op": ">",
        "value": 0
    },
    "then": {
        "type": "action",
        "name": "order_normal"
    },
    "else": {
        "type": "action",
        "name": "order_out_of_stock"
    }
}');
// 动态解释执行 JSON 规则
function executeRule($node, $context) {
    switch ($node->type) {
        case 'if':
            $left = getContextValue($context, $node->condition->field);
            $right = $node->condition->value;
            // 根据 $node->condition->op 进行比较...
            $result = compare($left, $right);
            return $result ? executeRule($node->then, $context) : executeRule($node->else, $context);
        case 'action':
            return call_user_func($node->name, $context);
    }
}

适用场景:需要绘制规则流程图的 BPM 系统、审批流、工作流引擎。 优点:业务人员可以搭建可视化流程,真正实现了“动态”。 缺点:开发成本最高(需要实现解析器、校验器、调试工具)。


🛡️ 安全建议(重要!)

  1. 不要用裸 eval():如果必须用,务必白名单函数(用 stripslashes 配合 preg_match 过滤),禁止 exec, system, shell_exec, file_get_contents 等危险函数。
  2. 数据校验:动态规则中的字段名必须与系统数据库字段严格匹配,使用映射表以防止注入。
  3. 缓存编译结果:如果规则比较复杂且频繁调用,建议将规则预编译为 PHP 数组缓存到文件或 Redis 中,避免每次请求都解析字符串。

总结建议

  • 为了快速改参,选 方案一(配置驱动),成本最低。
  • 为了运营配置多条件,选 方案二(表达式语言),性价比最高。
  • 为了复杂逻辑流转/工作流,选 方案四(JSON/流程图),虽然开发量大但是系统天花板高。
  • 如果只是改几个 if/else 的条件,方案三(规则引擎) 可能过度设计,不推荐。

如果是做 SaaS 多租户,优先考虑方案一 + 方案二的组合,既能快速响应运营需求,又能满足一定复杂性。

抱歉,评论功能暂时关闭!