如何递归计算嵌套布尔逻辑表达式数组的最终真值

9次阅读

如何递归计算嵌套布尔逻辑表达式数组的最终真值

本文介绍一种通用、高效的递归 php 函数,用于解析任意深度嵌套的 `and`/`or` 逻辑节点数组,准确计算其布尔结果,适用于 laravelphp 应用中的动态规则引擎或条件求值场景。

在构建动态权限控制、业务规则引擎或条件过滤器(如高级搜索、风控策略)时,常需将逻辑结构以 jsON 形式存储并运行时求值。上述数据结构本质上是一棵多叉逻辑表达式树:每个节点含 “nodeType” 字段(”and” 或 “or”),其余键(如 “0”, “1”, “3” 等)为子表达式——这些键名无语义,仅作索引,真正重要的是其值(布尔字面量或子节点对象)。

由于树的深度与分支数完全动态,迭代遍历极易出错且难以维护,递归是自然且最优的选择。核心思路是:

  • 基础情况(Base Case):若当前值为 true 或 false,直接返回;
  • 递归情况(Recursive Case):根据 nodeType 决定短路策略:
    • “or” 节点:只要任一子节点返回 true,立即返回 true(OR 短路);
    • “and” 节点:只要任一子节点返回 false,立即返回 false(AND 短路);
  • 收尾逻辑:若遍历完所有子节点均未触发短路,则 “or” 返回 false,”and” 返回 true(即默认值取逻辑恒等元)。

以下是经过验证、鲁棒性强的实现:

function evaluateBooleanExpression($expr): bool {     // 基础情况:已是布尔值,直接返回     if (is_bool($expr)) {         return $expr;     }      // 非数组或缺少 nodeType,视为无效节点(可按需抛异常)     if (!is_array($expr) || !isset($expr['nodeType'])) {         throw new InvalidArgumentException('Invalid expression: missing "nodeType" or not an array');     }      $isOrNode = $expr['nodeType'] === 'or';     $shortCircuitValue = $isOrNode; // OR 短路于 true;AND 短路于 false      // 遍历所有非 "nodeType" 的子项     foreach ($expr as $key => $value) {         if ($key === 'nodeType') {             continue;         }         $childResult = evaluateBooleanExpression($value);         if ($childResult === $shortCircuitValue) {             return $shortCircuitValue; // 触发短路         }     }      // 未短路:OR 全为 false → 返回 false;AND 全为 true → 返回 true     return !$shortCircuitValue; }

使用示例与验证

假设你从数据库或 API 获取如下 json 字符串(注意外层为单元素数组):

$json = '[     {         "nodeType": "and",         "0": {             "nodeType": "and",             "0": {                 "nodeType": "and",                 "1": true,                 "2": false             },             "3": true         },         "2": {             "nodeType": "or",             "4": false,             "5": true         }     } ]';  $data = json_decode($json, true); $result = evaluateBooleanExpression($data[0]); // 取首个元素 var_dump($result); // 输出: bool(false) ✅ 符合预期(最内层 and(1:true, 2:false) = false,导致顶层 and 整体为 false)

关键注意事项

  • ? 键名无关性:函数自动跳过 “nodeType” 键,其余所有键均视为子表达式入口,完全兼容 “0”, “1”, “3”, “4” 等任意数字或字符串键;
  • ? 严格类型安全:使用 is_bool() 判定基础值,避免 0/1、”true”/”false” 等松散类型干扰;
  • ? 短路优化:无需遍历整棵树,在满足逻辑条件时立即终止,性能随表达式复杂度提升而显著受益;
  • ? 错误防护:对缺失 nodeType 或非数组输入主动抛异常,便于调试与集成测试;
  • ? laravel 集成建议:可封装app/Helpers/LogicEvaluator.php 辅助函数,或定义为 LogicExpression 服务类,配合依赖注入使用。

该方案已通过多层嵌套(含 and→or→and→… 混合)、边界 case(纯叶子节点、空子节点等)充分验证,是生产环境中处理动态布尔逻辑表达式的可靠实践。

text=ZqhQzanResources