rogervila / php-simple-rules-engine
PHP 简单规则引擎
Requires
- php: ^8.0
Requires (Dev)
- phpstan/phpstan: ^1.0
- phpunit/phpunit: ^9.0 || ^10.0
- vimeo/psalm: ^5.0
README
PHP 简单规则引擎
关于
根据主题评估规则。
用法
该包期望一个主题和一组规则。
每个规则都必须是一个扩展 \SimpleRulesEngine\Rule
的类。
主题参数可以是任何类型的对象 (mixed
)
基本用法
规则返回一个包含由用户定义的 result
属性的 \SimpleRulesEngine\Evaluation
对象。
此外,用户可以定义 stop
属性的值以确定评估过程是否应该停止或继续。
在此示例中,由于我们只评估一个规则,因此 stop
属性的值不会影响评估过程。
use SimpleRulesEngine\Rule; use SimpleRulesEngine\Evaluation; use SimpleRulesEngine\RulesEngine; class FooRule extends Rule { public function evaluate(mixed $subject, ?Evaluation $previousEvaluation = null): Evaluation { return new Evaluation( result: $subject === 'foo', // mixed. It should contain the evaluation result defined by the user. stop: false, // false by default. When set to true, the evaluation process is stopped. ); } } $evaluation = RulesEngine::run( subject: 'foo', rules: [new FooRule()] ); var_dump($evaluation->getResult()); // bool(true) var_dump($evaluation->getRule()::class); // string(7) "FooRule"
高级用法
当评估多个规则时,您可以通过将 withHistory
参数设置为 true
来检索特定评估过程中评估的规则的历史记录。
最终的 \SimpleRulesEngine\Evaluation
对象将包含一个包含在评估过程中由规则返回的评估结果的 history
列表。
请查看 tests/RulesEngineTest.php
中的 test_evaluation_with_history
方法以获取更详细的实现。
use SimpleRulesEngine\Rule; use SimpleRulesEngine\Evaluation; use SimpleRulesEngine\RulesEngine; class RuleA extends Rule { // ... } class RuleB extends Rule { // ... } class RuleC extends Rule { // ... } $rules = [new RuleA(), new RuleB(), new RuleC()]; // Let's pretend that the final evaluation comes from RuleC() $evaluation = RulesEngine::run( subject: 'C', rules: $rules, withHistory: true ); var_dump(count($evaluation->getHistory())); // int(2) var_dump($evaluation->getHistory()[0]->getRule()::class); // string(5) "RuleA" var_dump($evaluation->getHistory()[1]->getRule()::class); // string(5) "RuleB"
递归使用
您可以将规则和规则数组传递给它们以递归地评估它们。
注意:此库的将来版本可能包含 Openswoole 支持,以并行化评估每个规则子集。
use SimpleRulesEngine\Evaluation; use SimpleRulesEngine\RulesEngine; $rules = [ new ARule(), // 0 new BRule(), // 1 [ new AARule(), // 2 [ new AAARule(), // 3 new AABRule(), // 4 new AACRule(), // 5 ] ], new CRule() // 6 ]; $evaluation = RulesEngine::run( subject: '...', rules: $rules );
示例
这些示例非常简单,仅用于演示目的,但它们展示了该包附带的基本功能。
有一个名为 durable rules 的 Python 规则引擎,它包含一些示例。我们将使用此包重新创建它们。
模式匹配
根据其号码找到信用卡类型。
请查看 tests/RulesEngineTest.php
中的 test_match_example_with_cards
方法以获取更详细的实现。
use SimpleRulesEngine\Rule; use SimpleRulesEngine\Evaluation; use SimpleRulesEngine\RulesEngine; $amex = '375678956789765'; $visa = '4345634566789888'; $mastercard = '2228345634567898'; $invalid = uniqid('invalid card '); class AmexRule extends Rule { public function evaluate(mixed $subject, ?Evaluation $previousEvaluation = null): Evaluation { return new Evaluation( result: $result = preg_match('/^3[47][0-9]{13}$/', strval($subject)) === 1 ? 'amex' : null, stop: $result !== null, ); } }; class VisaRule extends Rule { public function evaluate(mixed $subject, ?Evaluation $previousEvaluation = null): Evaluation { return new Evaluation( result: $result = preg_match('/^4[0-9]{12}(?:[0-9]{3})?$/', strval($subject)) === 1 ? 'visa' : null, stop: $result !== null, ); } }; class MastercardRule extends Rule { public function evaluate(mixed $subject, ?Evaluation $previousEvaluation = null): Evaluation { return new Evaluation( result: $result = preg_match('/(5[1-5][0-9]{2}|222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|2720)[0-9]{12}/', strval($subject)) === 1 ? 'mastercard' : null, stop: $result !== null, ); } }; $rules = [new VisaRule(), new AmexRule(), new MastercardRule()]; shuffle($rules); // Rules should apply always, the order does not matter $evaluation = RulesEngine::run($amex, $rules); var_dump($evaluation->getResult()); // string(4) "amex" var_dump($evaluation->getRule()::class); // string(8) "AmexRule" $evaluation = RulesEngine::run($visa, $rules); var_dump($evaluation->getResult()); // string(4) "visa" var_dump($evaluation->getRule()::class); // string(8) "VisaRule" $evaluation = RulesEngine::run($mastercard, $rules); var_dump($evaluation->getResult()); // string(10) "mastercard" var_dump($evaluation->getRule()::class); // string(14) "MastercardRule" $evaluation = RulesEngine::run($invalid, $rules); var_dump($evaluation->getResult()); // NULL var_dump($evaluation->getRule()::class); // Since we are using shuffle here, the rule applied can be any of the rules previously passed
事实集
根据事实找到动物。
在这种情况下,我们将比较当前规则结果与先前评估结果。如果它们匹配,我们将停止评估过程。
请查看 tests/RulesEngineTest.php
中的 test_facts_example
方法以获取更详细的实现。
use SimpleRulesEngine\Rule; use SimpleRulesEngine\Evaluation; use SimpleRulesEngine\RulesEngine; class Animal { public string $eats = ''; public string $lives = ''; public string $color = ''; }; $frog = new Animal(); $frog->eats = 'flies'; $frog->lives = 'water'; $frog->color = 'green'; $bird = new Animal(); $bird->eats = 'worms'; $bird->lives = 'nest'; $bird->color = 'black'; class EatsRule extends Rule { public const FACTS = ['flies' => 'frog', 'worms' => 'bird']; public function evaluate(mixed $subject, ?Evaluation $previousEvaluation = null): Evaluation { $previousResult = $previousEvaluation?->getResult(); $currentResult = self::FACTS[$subject?->eats]; return new Evaluation( result: $currentResult, stop: $previousResult === $currentResult, ); } }; class LivesRule extends Rule { public const FACTS = ['water' => 'frog', 'nest' => 'bird']; public function evaluate(mixed $subject, ?Evaluation $previousEvaluation = null): Evaluation { $previousResult = $previousEvaluation?->getResult(); $currentResult = self::FACTS[$subject?->lives]; return new Evaluation( result: $currentResult, stop: $previousResult === $currentResult, ); } }; class ColorRule extends Rule { public const FACTS = ['green' => 'frog', 'black' => 'bird']; public function evaluate(mixed $subject, ?Evaluation $previousEvaluation = null): Evaluation { $previousResult = $previousEvaluation?->getResult(); $currentResult = self::FACTS[$subject?->color]; return new Evaluation( result: $currentResult, stop: $previousResult === $currentResult, ); } }; $rules = [new EatsRule(), new LivesRule(), new ColorRule()]; shuffle($rules); // Rules should apply always, the order does not matter $evaluation = RulesEngine::run($frog, $rules); var_dump($evaluation->getResult()); // string(4) "frog" $evaluation = RulesEngine::run($bird, $rules); var_dump($evaluation->getResult()); // string(4) "bird"
作者
由 Roger Vilà 创建
许可证
PHP Simple Rules Engine 是开源软件,许可协议为 MIT 许可证。
图标由 Gregor Cresnar 制作,来自 www.flaticon.com