PHP|PHP 实现规则引擎

1、规则引擎简介
我们在写业务代码经常遇到需要一大堆if/else,会导致代码可读性大大降低,有没有一种方法可以避免代码中出现大量的判断语句呢?答案是用规则引擎。
规则引擎是一种推理引擎,它是根据已有的事实,从规则知识库中匹配规则,并处理存在冲突的规则,执行最后筛选通过的规则。因此,规则引擎是人工智能(AI)研究领域的一部分,具有一定的选择判断性、人工智能性和富含知识性。
2、核心思想
规则就是一堆条件传入,这些条件之间有与或的逻辑关系,根据引擎判断和之后,进行后续的动作。
3、基本架构思想
规则文件 + data => 后端解析condition => action
流程图

PHP|PHP 实现规则引擎
文章图片

image.png
4、UML图
PHP|PHP 实现规则引擎
文章图片

rule.png
5、用php实现
目录结构
PHP|PHP 实现规则引擎
文章图片

image.png
首先规则文件在此用目前流行的json文件表示
举例 rule.json

{ "condition": { "1": { "type": "tag", "con": "user = 1" }, "2": { "type": "tag", "con": "user > 1" } }, "logical": "1 & 2", "action": ["action1", "action2"] }

ConditionInterface

ActionInterface
interface ActionInterface {public function call(); }

condition容器
logicalArr = explode(' ', $logical); }public function __set($param, $condition) { $this->conditions[$param] = $condition; }public function check(&$data) { //docheck foreach ($this->conditions as $param => $condition) { $this->results[$param] = $condition->check($data); } $i = 0; $commandArr = $this->logicalArr; foreach ($commandArr as &$str) { if (preg_match('/^\d+$/', $str)) { $str = $this->results[$i+1]; $i++; } } $command = implode('', $commandArr); $result = eval('return '.$command.'; '); return $result; } }

规则类
|\<|\>=|\<=)\s*\'?[a-zA-Z0-9\-\s\:]+\'?)|(in\s*\[(\'?[a-zA-Z0-9\-]+\'?\s*\,?\s*)+\]))\)$/", $rule, $matches)) { $attribute = $matches[1]; if (strpos($rule, 'in') !== false) { $rArr = explode('in', $rule); $paramStr = str_replace(array('[', ']', ')', ' ', '\'', '\''), '', $rArr[1]); $paramArr = explode(',',$paramStr); $res = in_array($obj->$attribute, $paramArr); } else { $r = $rule; if (preg_match('/[a-zA-Z0-9_]+\s*=/', $rule, $params)) $r = str_replace('=', '==', $rule); $atibute = $obj->$attribute; $res = eval('return ($atibute'.str_replace($attribute, '', substr($r, 1))."; "); } } return $res; }public static function check_rule($ruleStr, $ruleClass) { $GLOBALS['log']->fatal('start-check-rule-------'.$ruleStr); if (preg_match_all("/\([a-zA-Z0-9_]+\s*(((=|\>|\<|\>=|\<=)\s*\'?[a-zA-Z0-9\-\s\:]+\'?)|(in\s*\[(\'?[a-zA-Z0-9\-]+\'?\s*\,?\s*)+\]))\)/", $ruleStr, $rules)) { foreach ($rules[0] as $rule) { $ruleRes = self::check($rule, $ruleClass); $ruleStr = str_replace($rule, (int)$ruleRes, $ruleStr); } $GLOBALS['log']->fatal('the-end-rule-----'.$ruleStr); if (!preg_match('/[^(0|1|and|or|!|\(|\)|\s)]/', $ruleStr)) { return eval('return '.str_replace(array('and', 'or'), array(' and ', ' or '), $ruleStr)."; "); } } return false; } }/** * 调用示例 $class = new check_rule_class(); $class->a = '2'; $class->b = 5; $res = rule::check_rule("!(a=2) or (b in [2, '5'])", $class); var_dump($res); */

入口文件
setLogical($arr['logical']); foreach ($arr['condition'] as $k => $condition) { $file = $condition['type']; require_once 'condition/'.$file.'.php'; $conContainer->$k = new $file($condition['con']); }$actClasses = $arr['action']; $actions = []; foreach ($actClasses as $actClass) { require_once 'action/'.$actClass.'.php'; $actions[] = new $actClass(); } $rule = new Rule($conContainer, $actions); $rule->run();

【PHP|PHP 实现规则引擎】

    推荐阅读