这种规则解释一般不会直接在数据库中完成,最终还是会在你check_rules_against_data这样的解释器中完成,那绝对没问题。
将所有规则直接写在一个或多个 php 文件中是很常见的(当然还有一些代码,例如if ($rule) { echo $message; })。它通常比每次动态评估每个规则要快(请记住,数据库也必须这样做)。如何对过滤器进行编码取决于您的需要;您可以坚持您的规则格式,您可以只显示完整的 php 代码并让用户对其进行编辑,您可以将它们拆分并使用数据库设计,例如验证变量是否存在(例如,参见下面我的扩展rule_term-table 或 completeitpro 的答案)。所有这些都可以正常工作。
如果你愿意,或者如果你想测试它,你可以在你的数据库中做一些预选。有很多方法可以做到这一点,并且有很多方法可以针对特殊情况对其进行优化,这在很大程度上取决于您实际想要做什么,所以我只描述一种方法,给您一个想法。
你的变量看起来你会有很多,但它们都是整数(所以拥有可乐并不意味着:Items[x]='COCA',而是coca=1),所以你可以把它们和规则放在表格中像这样:
变量
variableid | variablename | variabletype
----------------------------------------
1 | errors | 1
2 | level | 1
3 | score | 1
用户变量
userid | variableid | valueint
-------------------------------------
1 | 1 | 0
1 | 2 | 6
1 | 3 | 10
2 | 1 | 3
2 | 3 | 10
3 | 1 | 0
3 | 2 | 6
3 | 3 | 10
4 | 1 | 0
4 | 2 | 5
规则
ruleid | mincount | message
---------------------------
1 | 2 | Senior player -> AND (2 terms have to fit)
2 | 1 | Border line player -> OR (any 1 term can fit)
规则术语
ruleid | variableid | minvalueint | maxvalueint
-----------------------------------------------
1 | 1 | 0 | 0 -> error == 0
1 | 2 | 6 | 9999 -> level > 5
2 | 1 | 3 | 3 -> error == 3
2 | 3 | 10 | 10 -> score == 10
使用这些规则,您现在可以预先选择命中的规则:
select user_variable.userid, rule.ruleid, count(*) as cntfulfilled,
max(rule.mincount) as mincnt, max(rule.message) as message
from rule_term
join rule
on rule_term.ruleid = rule.ruleid
join user_variable
on rule_term.variableid = user_variable.variableid
and rule_term.minvalueint <= user_variable.valueint
and rule_term.maxvalueint >= user_variable.valueint
group by user_variable.userid, rule.ruleid
having count(*) >= max(rule.mincount);
这应该计算每个用户和每个规则,该规则有多少子项被满足。如果我没记错的话,应该是这样的:
userid | ruleid | cntfulfilled | mincnt | message
--------------------------------------------------
1 | 1 | 2 | 2 | Senior player
1 | 2 | 1 | 1 | Border line player
2 | 2 | 2 | 1 | Border line player
3 | 1 | 2 | 2 | Senior player
要表达AND,mincnt应该是所有子项的数量,对于OR,它将是1。用普通AND或OR构建规则,这已经是完整的了测试。
对于更复杂的规则,您必须能够在 php 中重新创建规则以将其放入您的检查功能中。你可以例如将其编码在如下表中:
扩展rule_term-table:
ruleid | pos | cond | var.id | min | max
--------------------------------------------
3 | 1 | 1 | 0 | 0 | 0 -> (
3 | 2 | 0 | 1 | 1 | 1 -> error == 1
3 | 3 | 4 | 2 | 5 | 5 -> AND level == 5
3 | 4 | 2 | 0 | 0 | 0 -> )
3 | 5 | 5 | 3 | 10 | 10 -> OR score == 10
我使用 cond=1: (, cond=2: ), cond=3: NOT, cond=4: AND, cond=5: OR。 (有更好的编码方法,例如只表达逻辑并将其分组到嵌套的AND-subgroups 中,但它不会在这里改进任何东西)。
这将允许您仍然预先选择可能适合的规则,以获取您必须在 php 中分析的规则(您不能再使用 mincnt,因为 mincnt 将是 1,即使只是 error == 1,而不仅仅是 @987654341 @)。
您可以向其中添加更多内容:您可以添加字符串变量类型(将列 valuestr 添加到 user_variable 和 rule_term 并调整连接)或“NOT”标志,您可以添加更多如果您能够在 rule_term-table 中的行中表达它们(例如,组合 2 个变量并在双连接中检查 2 个变量),则对您的连接有复杂的条件。
这有点困难,但您可能希望使用左连接和一些额外的逻辑来比较不存在的变量(例如,如果您不想为每个人设置变量 coca,只为那些有(或有)可乐。
如果您想使用水平变量(固定数量的变量,每个变量在一列中),您应该对规则术语(每个变量的最小/最大值列)执行相同的操作并调整连接以检查每个列。
这只是一个一般性的想法,显然您有很多替代方案可以做到这一点,最佳选择和优化很大程度上取决于您的实际需求,并花更多时间考虑您的数据库设计(或如何生成动态php 文件)稍后会减少挫败感(很多)或提高速度(很多)。我会再次提醒您,测试生成动态 php 文件的选项 - 这通常会快很多。