本文目录导读:

- 方案一:配置驱动(适合简单规则)
- 方案二:表达式语言(适合中等复杂规则)
- 方案三:规则引擎库(适合复杂业务流转)
- 方案四:DSL(领域特定语言)+ 脚本执行(最灵活,类似低代码)
- 🛡️ 安全建议(重要!)
- 总结建议
在 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 系统、审批流、工作流引擎。 优点:业务人员可以搭建可视化流程,真正实现了“动态”。 缺点:开发成本最高(需要实现解析器、校验器、调试工具)。
🛡️ 安全建议(重要!)
- 不要用裸
eval():如果必须用,务必白名单函数(用stripslashes配合preg_match过滤),禁止exec,system,shell_exec,file_get_contents等危险函数。 - 数据校验:动态规则中的字段名必须与系统数据库字段严格匹配,使用映射表以防止注入。
- 缓存编译结果:如果规则比较复杂且频繁调用,建议将规则预编译为 PHP 数组缓存到文件或 Redis 中,避免每次请求都解析字符串。
总结建议
- 为了快速改参,选 方案一(配置驱动),成本最低。
- 为了运营配置多条件,选 方案二(表达式语言),性价比最高。
- 为了复杂逻辑流转/工作流,选 方案四(JSON/流程图),虽然开发量大但是系统天花板高。
- 如果只是改几个
if/else的条件,方案三(规则引擎) 可能过度设计,不推荐。
如果是做 SaaS 多租户,优先考虑方案一 + 方案二的组合,既能快速响应运营需求,又能满足一定复杂性。