简体中文 | English
A lightweight, easy-to-use PHP rule engine supporting multi-condition combinations and dynamic rule execution — ideal for business logic evaluation and data validation.
This project has been parsed by Zread. Click to explore the project structure and code navigation.
- Clean API: Build and execute rules in just a few lines with
Rule+Engine, supporting AND / OR combination logic. - Rich Built-in Operators: 17 operators out of the box covering comparison, string, array, and date scenarios.
- Highly Extensible: Register custom operators by implementing the
OperatorInterfaceto handle specialized business needs. - Decoupled Rules and Data: Rule definitions are fully separated from data evaluation, supporting arrays, objects, and more.
- Detailed Evaluation Feedback:
evaluateWithDetailsreturns the pass/fail status of each rule, making debugging and logging straightforward.
- PHP >= 8.1
- nesbot/carbon ^3.9 (required by date operators)
composer require hejunjie/simple-rule-engineuse Hejunjie\SimpleRuleEngine\Rule;
use Hejunjie\SimpleRuleEngine\Engine;
// 1. Define rules
$rules = [
new Rule('age', '>=', 18, 'Age must be 18 or older'),
new Rule('country', '==', 'SG', 'Country must be Singapore'),
];
// 2. Prepare data
$data = [
'age' => 20,
'country' => 'SG',
];
// 3. Evaluate
$result = Engine::evaluate($rules, $data, 'AND'); // trueEngine::evaluate() accepts a list of rules, data, and a combination strategy, returning a boolean.
$rules = [
new Rule('score', '>=', 60, 'Score is passing'),
new Rule('score', '<', 100, 'Score is not perfect'),
];
$data = ['score' => 85];
// AND: all rules must pass
Engine::evaluate($rules, $data, 'AND'); // true
// OR: at least one rule must pass
Engine::evaluate($rules, $data, 'OR'); // trueEngine::evaluateWithDetails() returns the evaluation result for each rule:
$rules = [
new Rule('age', '>=', 18, 'Age must be 18 or older'),
new Rule('vip', '==', true, 'Must be a VIP user'),
];
$data = ['age' => 20, 'vip' => false];
$details = Engine::evaluateWithDetails($rules, $data);
// [
// ['description' => 'Age must be 18 or older', 'passed' => true],
// ['description' => 'Must be a VIP user', 'passed' => false],
// ]If you need more flexible composition (e.g., reusing the same group of rules across different scenarios), you can use RuleGroup directly:
use Hejunjie\SimpleRuleEngine\RuleGroup;
$group = new RuleGroup([
new Rule('status', '==', 'active', 'Status is active'),
new Rule('level', '>=', 3, 'Level is 3 or above'),
], 'AND');
$data = ['status' => 'active', 'level' => 5];
$group->evaluate($data); // true
$group->evaluateWithDetails($data); // Returns detailed evaluation arrayImplement the OperatorInterface and register through OperatorFactory:
use Hejunjie\SimpleRuleEngine\Interface\OperatorInterface;
use Hejunjie\SimpleRuleEngine\OperatorFactory;
class ModOperator implements OperatorInterface
{
public function evaluate(mixed $fieldValue, mixed $ruleValue): bool
{
return $fieldValue % $ruleValue === 0;
}
public function name(): string
{
return 'mod';
}
}
// Register
OperatorFactory::getInstance()->register(new ModOperator());
// Use
$rule = new Rule('number', 'mod', 3, 'Number is divisible by 3');
$rule->evaluate(['number' => 9]); // true| Operator | Description | Example Value |
|---|---|---|
== |
Equal to | 18 |
!= |
Not equal to | 18 |
> |
Greater than | 18 |
>= |
Greater than or equal to | 18 |
< |
Less than | 18 |
<= |
Less than or equal to | 18 |
| Operator | Description | Example Value |
|---|---|---|
in |
Value in array | ['SG', 'MY', 'TH'] |
not_in |
Value not in array | ['SG', 'MY', 'TH'] |
| Operator | Description | Example Value |
|---|---|---|
contains |
Contains substring | 'admin' |
not_contains |
Does not contain substring | 'admin' |
start_swith |
Starts with | 'VIP_' |
end_swith |
Ends with | '@example.com' |
| Operator | Description | Example Value |
|---|---|---|
between |
Value within range | [18, 65] |
not_between |
Value outside range | [18, 65] |
| Operator | Description | Example Value |
|---|---|---|
before_date |
Date is before | '2025-01-01' |
after_date |
Date is after | '2025-01-01' |
date_equal |
Date is equal to | '2025-01-01' |
Date operators are powered by Carbon and support all common date formats as well as timestamps.
- Form Data Validation: Dynamically validate user-submitted fields against conditions.
- Business Rule Evaluation: Order status transitions, campaign eligibility, access control, and more.
- Data Filtering: Filter datasets based on predefined rules.
- Config-Driven Logic: Define rules via configuration files or databases for flexible business logic.
php-simple-rule-engine/
├── src/
│ ├── Engine.php # Rule engine entry point (static facade)
│ ├── Rule.php # Single rule
│ ├── RuleGroup.php # Rule group (supports AND/OR composition)
│ ├── OperatorFactory.php # Operator factory (singleton, manages registration)
│ ├── Interface/
│ │ └── OperatorInterface.php # Operator interface
│ └── Operators/ # Built-in operator implementations
│ ├── EqualOperator.php
│ ├── NotEqualOperator.php
│ ├── GreaterThanOperator.php
│ ├── GreaterThanOrEqualOperator.php
│ ├── LessThanOperator.php
│ ├── LessThanOrEqualOperator.php
│ ├── InOperator.php
│ ├── NotInOperator.php
│ ├── ContainsOperator.php
│ ├── NotContainsOperator.php
│ ├── StartsWithOperator.php
│ ├── EndsWithOperator.php
│ ├── BetweenOperator.php
│ ├── NotBetweenOperator.php
│ ├── BeforeDateOperator.php
│ ├── AfterDateOperator.php
│ └── DateEqualOperator.php
├── tests/
│ └── Operators/ # Operator unit tests
├── composer.json
├── phpunit.xml
└── README.md
composer install
./vendor/bin/phpunitIf this project helps you, a Star ⭐ would be much appreciated!
For questions or suggestions, feel free to open an Issue. Let's make it better together.