不知道你有没有这种感觉:一个业务功能看起来很简单,但判断条件却一大堆。
什么用户状态、配置项、商品属性、会员等级……
一大堆 if​ / else​ 交织在一起,越写越乱,稍微改一个逻辑就要担心影响其他地方。

我之前就遇到这样的情况,一开始还能忍,后来干脆决定:不如自己写一个简单的规则引擎,专门用来处理这些组合判断。

于是就有了这个项目:hejunjie/simple-rule-engine


🚀 这个规则引擎能干嘛?

一句话总结:
这是一个轻量、易用的 PHP 规则引擎,支持多条件组合、动态规则执行,适合业务规则判断、数据校验等场景。

适合用在你项目中的这些地方:

  • 复杂业务的多条件判断(比如用户是否满足某个活动要求)
  • 数据入库前的规则校验
  • 自定义逻辑的配置化、结构化处理
  • 写得一手 if 地狱,想抽出来整整齐齐 😅

🌟 为什么要做它?

在实际业务中,很多业务判断逻辑其实都可以归纳为:“一堆字段 + 一些规则 + 多个条件组合”。

原本我们可能是这么写的:

1
2
3
4
5
6
7
if (
$user['status'] === 'active' &&
$user['age'] >= 18 &&
in_array($user['role'], ['admin', 'editor'])
) {
// ...
}

现在可以这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 定义规则
$rules = [
new Rule('age', '>=', 18, '年龄必须大于等于18岁'),
new Rule('status', '==', 'active', '状态必须为active'),
new Rule('role', 'in', ['admin', 'editor'], '角色需拥有权限'),
];
// 评估结果
$result = Engine::evaluate($rules, $user, 'AND'); // 返回 true 或 false

// 获取详细评估信息(用于获取每条规则的执行情况)
$details = Engine::evaluateWithDetails($rules, $user);
/*
返回示例:
[
['description' => '年龄必须大于等于18岁', 'passed' => true],
['description' => '状态必须为active', 'passed' => true],
['description' => '角色需拥有权限', 'passed' => true]
]
*/

是不是整洁多了?而且如果你把规则放数据库,就能实现“业务判断配置化”了。


🧩 项目特点

  • 轻量易用:无依赖,无框架限制,简单几行就能用
  • 🔌 工厂注册机制:你可以自己写新的操作符(Operator)注册进来
  • 📦 内置常用操作符:多数常用操作符都支持(可见文章末尾操作符支持列表)
  • 🧠 可组合、多条件支持:支持 AND / OR 关系组合,扩展多套规则逻辑很方便

📦 安装方法

1
composer require hejunjie/simple-rule-engine

🛠️ 示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
use Hejunjie\SimpleRuleEngine\Rule;
use Hejunjie\SimpleRuleEngine\Engine;

// 定义规则
$rules = [
new Rule('age', '>=', 18, '年龄必须大于等于18岁'),
new Rule('status', '==', 'active', '状态必须为active'),
new Rule('role', 'in', ['admin', 'editor'], '角色需拥有权限'),
];

$data = ['age' => 20, 'country' => 'China'];

// 简单判断是否通过全部规则
if (Engine::evaluate($rules, $data, 'AND')) {
echo '符合规则';
}

// 获取每一条规则是否通过的详情
foreach (Engine::evaluateWithDetails($rules, $data) as $detail) {
echo $detail['description'] . ':' . ($detail['passed'] ? '✅ 通过' : '❌ 未通过') . PHP_EOL;
}

🔌 自定义操作符

你可以自由的去实现自己的判断逻辑,指定一个操作符,并自由的插入到你的规则中

仅需要实现 OperatorInterface​ 接口,并通过 OperatorFactory​ 注册即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
use Hejunjie\SimpleRuleEngine\Interface\OperatorInterface;
use Hejunjie\SimpleRuleEngine\OperatorFactory;

class CustomizeOperator implements OperatorInterface
{
/**
* 评估方法
*
* @param mixed $fieldValue 用户输入数据
* @param mixed $ruleValue 对比数据
*
* @return bool
*/
public function evaluate(mixed $fieldValue, mixed $ruleValue): bool
{
// TODO: 实现判断逻辑
}

/**
* 操作符名称
*
* @return string
*/
public function name(): string
{
return 'customize';
}
}

// 注册自定义操作符 customize
$factory = OperatorFactory::getInstance();
$factory->register(new CustomizeOperator());

// 可以在定义规则时使用 customize
$rules = [
new Rule('field', 'customize', 'value', '自定义规则描述'),
...
...
];

// Engine::evaluate($rules, $data, 'AND')
// Engine::evaluateWithDetails($rules, $data)

🧩 内置操作符列表

操作符 描述 额外说明
== 等于
!= 不等于
> 大于
>= 大于等于
< 小于
<= 小于等于
in 包含于集合中 数组:[内容 1,内容 2,…]
not_in 不包含于集合中 数组:[内容 1,内容 2,…]
contains 包含字符串
not_contains 不包含字符串
start_swith 以指定字符串开头
end_swith 以指定字符串结尾
between 在指定范围内 数组:[最大值,最小值]
not_between 不在指定范围内 数组:[最大值,最小值]
before_date 日期早于 任意常规日期格式,包括时间戳均可
after_date 日期晚于 任意常规日期格式,包括时间戳均可
date_equal 日期相等 任意常规日期格式,包括时间戳均可

🤔 总结一下

这个规则引擎不是为了解决多么高级的技术难题,它只是一个更优雅的解决方式
如果你也遇到过类似的 if/else 困扰,希望这个小工具能帮上你一点忙。


欢迎 Star、Issue、PR,一起完善它 🙌
如果你觉得有帮助,点个赞我会更有动力更新下去~