含AND与OR的复合条件表达式求值方案咨询
条件求值可行方案
1. 核心思路:用抽象语法树(AST)处理优先级逻辑
原有的数组拆分方式无法处理括号、OR/AND优先级问题,必须先将条件字符串解析成AST,再递归求值。AST能清晰表达逻辑层级:
- 括号内的OR逻辑作为独立子节点,优先级高于外部的AND
- 顶层逗号分隔的条件都是AND节点,内部|分隔的是OR节点
比如示例条件E==test3,(F==test4|F==test5),username!=abc对应的AST结构:
AND节点 ├─ 比较节点:E == test3 ├─ OR节点 │ ├─ 比较节点:F == test4 │ └─ 比较节点:F == test5 └─ 比较节点:username != abc
2. 具体实现步骤
第一步:解析条件字符串生成AST
- 按逗号分割顶层AND条件,区分普通比较式和带括号的子表达式
- 对带括号的子表达式,去掉括号后按|分割生成OR子节点
- 每个基础比较式拆分为左值、操作符、右值(比如
E==test3拆为E、==、test3)
第二步:递归遍历AST求值
写递归函数处理不同类型节点:
- 比较节点:直接取变量当前值与右值做对应运算(==/!=等),返回布尔结果
- OR节点:遍历子节点,只要一个子节点为true则返回true,全false才返回false
- AND节点:遍历子节点,只要一个子节点为false则返回false,全true才返回true
PHP示例代码:
// 构建AST示例 $ast = [ 'type' => 'AND', 'children' => [ ['type' => 'COMPARE', 'left' => 'E', 'op' => '==', 'right' => 'test3'], [ 'type' => 'OR', 'children' => [ ['type' => 'COMPARE', 'left' => 'F', 'op' => '==', 'right' => 'test4'], ['type' => 'COMPARE', 'left' => 'F', 'op' => '==', 'right' => 'test5'] ] ], ['type' => 'COMPARE', 'left' => 'username', 'op' => '!=', 'right' => 'abc'] ] ]; // 递归求值函数 function evaluateAST($ast, $variables) { switch ($ast['type']) { case 'COMPARE': $leftVal = $variables[$ast['left']] ?? null; $rightVal = $ast['right']; switch ($ast['op']) { case '==': return $leftVal == $rightVal; case '!=': return $leftVal != $rightVal; // 可扩展>、<等操作符 } break; case 'OR': foreach ($ast['children'] as $child) { if (evaluateAST($child, $variables)) return true; } return false; case 'AND': foreach ($ast['children'] as $child) { if (!evaluateAST($child, $variables)) return false; } return true; } return false; }
替代方案:转成目标语言表达式求值
如果不想手写AST解析,可以把条件字符串转换成目标语言的可执行代码(需严格过滤避免注入):
比如将示例条件转成PHP表达式:
$safeCondition = "(\$vars['E'] == 'test3') && ((\$vars['F'] == 'test4') || (\$vars['F'] == 'test5')) && (\$vars['username'] != 'abc')"; $result = eval("return $safeCondition;");
注意:必须限制输入只能包含指定变量名、合法操作符和常量,杜绝恶意代码注入风险。
内容的提问来源于stack exchange,提问作者GreenGrassTunnel
相关产品推荐
相关产品推荐

