PHPackages                             rogervila/php-simple-rules-engine - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. rogervila/php-simple-rules-engine

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

rogervila/php-simple-rules-engine
=================================

PHP Simple Rules Engine

1.1.0(2y ago)51.8k↓45.2%MITPHPPHP ^8.0CI passing

Since Aug 29Pushed 5mo ago1 watchersCompare

[ Source](https://github.com/rogervila/php-simple-rules-engine)[ Packagist](https://packagist.org/packages/rogervila/php-simple-rules-engine)[ Docs](https://github.com/rogervila/php-simple-rules-engine)[ RSS](/packages/rogervila-php-simple-rules-engine/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (2)Dependencies (3)Versions (3)Used By (0)

[![PHP Simple Rules Engine](https://camo.githubusercontent.com/a89cb7f4a8a8ecc04f9e429e9f72b23cb3d939155d8a20865237e5040906c6f4/68747470733a2f2f726f67657276696c612e65732f7374617469632f696d672f707974686f6e5f73696d706c655f72756c65735f656e67696e652e706e67)](https://camo.githubusercontent.com/a89cb7f4a8a8ecc04f9e429e9f72b23cb3d939155d8a20865237e5040906c6f4/68747470733a2f2f726f67657276696c612e65732f7374617469632f696d672f707974686f6e5f73696d706c655f72756c65735f656e67696e652e706e67)

[![Build Status](https://github.com/rogervila/php-simple-rules-engine/workflows/build/badge.svg)](https://github.com/rogervila/php-simple-rules-engine/actions)[![StyleCI](https://camo.githubusercontent.com/76e0bf78be0c11ef4c79b0b2d25268c2b3486d06831f38f89f0a1a6e1f5b8960/68747470733a2f2f6769746875622e7374796c6563692e696f2f7265706f732f3638343530333130352f736869656c643f6272616e63683d6d61696e)](https://github.styleci.io/repos/684503105)[![Quality Gate Status](https://camo.githubusercontent.com/6573e5db2a71e5bc9ab43a2f61a4daed6c2ba1b5489acd5e75fd7765f8c0556a/68747470733a2f2f736f6e6172636c6f75642e696f2f6170692f70726f6a6563745f6261646765732f6d6561737572653f70726f6a6563743d726f67657276696c615f7068702d73696d706c652d72756c65732d656e67696e65266d65747269633d616c6572745f737461747573)](https://sonarcloud.io/dashboard?id=rogervila_php-simple-rules-engine)[![Coverage](https://camo.githubusercontent.com/3a3716a200e718de2b5c0151ff13a09622ca58e8d6acba4686befed471a8568b/68747470733a2f2f736f6e6172636c6f75642e696f2f6170692f70726f6a6563745f6261646765732f6d6561737572653f70726f6a6563743d726f67657276696c615f7068702d73696d706c652d72756c65732d656e67696e65266d65747269633d636f766572616765)](https://sonarcloud.io/dashboard?id=rogervila_php-simple-rules-engine)

[![Latest Stable Version](https://camo.githubusercontent.com/89a27e4733fb62955bef9e187d5754a069be14ed801dccba8e91d47b93416bb7/68747470733a2f2f706f7365722e707567782e6f72672f726f67657276696c612f7068702d73696d706c652d72756c65732d656e67696e652f762f737461626c65)](https://packagist.org/packages/rogervila/php-simple-rules-engine)[![Total Downloads](https://camo.githubusercontent.com/ef1b5b50dc05777bf5d3b9700e11357ac81f7c7399c3f2e527f8a563df62d024/68747470733a2f2f706f7365722e707567782e6f72672f726f67657276696c612f7068702d73696d706c652d72756c65732d656e67696e652f646f776e6c6f616473)](https://packagist.org/packages/rogervila/php-simple-rules-engine)[![License](https://camo.githubusercontent.com/92eb74d6bfb53cb0bbbe8ac9a8b5c09479423ea1feb33b13d892c23a839436f1/68747470733a2f2f706f7365722e707567782e6f72672f726f67657276696c612f7068702d73696d706c652d72756c65732d656e67696e652f6c6963656e7365)](https://packagist.org/packages/rogervila/php-simple-rules-engine)

PHP Simple Rules Engine
=======================

[](#php-simple-rules-engine)

About
-----

[](#about)

Evaluate rules based on a subject.

Usage
-----

[](#usage)

The package expects a subject and a list of rules.

Each rule must be a class that extends `\SimpleRulesEngine\Rule`.

The subject parameter can be any type of object (`mixed`)

### Basic usage

[](#basic-usage)

Rules return a `\SimpleRulesEngine\Evaluation` object that should contain a `result` property defined by the user.

Also, the user can define the value of the `stop` property to determine if the evaluation process should stop or continue.

In this example, the `stop` property value does not affect the evaluation process since we are evaluating only one rule.

```
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"
```

### Advanced usage

[](#advanced-usage)

When evaluating multiple rules you can retrieve the history of the rules evaluated for a specific evaluation process by passing the `withHistory` parameter as `true`.

The final `\SimpleRulesEngine\Evaluation` object will contain a `history` list with evaluations returned by the rules evaluated during the evaluation process.

Check `test_evaluation_with_history` method on `tests/RulesEngineTest.php` for a more detailed implementation.

```
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"
```

### Recursive usage

[](#recursive-usage)

You might pass rules and array of rules to recursively evaluate them.

> Note: A future version of this library might come with Openswoole support to parallelize the evaluation of each subset of rules.

```
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
);
```

Examples
--------

[](#examples)

The examples are very simple for demo purposes, but they show the basic features this package comes with.

There is a python rules engine called [durable rules](https://github.com/jruizgit/rules) that comes with some examples. We will recreate them with this package.

### Pattern matching

[](#pattern-matching)

Find a credit card type based on its number.

Check `test_match_example_with_cards` method on `tests/RulesEngineTest.php` for a more detailed implementation.

```
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
```

### Set of facts

[](#set-of-facts)

Find an animal based on facts.

In this case, we will compare the current rule result with the previous evaluation result. If they match, we stop the evaluation process.

Check `test_facts_example` method on `tests/RulesEngineTest.php` for a more detailed implementation.

```
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"
```

Author
------

[](#author)

Created by [Roger Vilà](https://rogervila.es)

License
-------

[](#license)

PHP Simple Rules Engine is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).

Icons made by [Gregor Cresnar](https://www.flaticon.com/authors/gregor-cresnar "Gregor Cresnar") from [www.flaticon.com](https://www.flaticon.com/ "Flaticon")

###  Health Score

35

—

LowBetter than 80% of packages

Maintenance47

Moderate activity, may be stable

Popularity25

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity49

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 55.6% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~20 days

Total

2

Last Release

973d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/351443b7d23e94fcf31b250db90f0b9578cc9fd8e0cefbed9666467e3e9cb571?d=identicon)[rogervila](/maintainers/rogervila)

---

Top Contributors

[![rogervila](https://avatars.githubusercontent.com/u/6053012?v=4)](https://github.com/rogervila "rogervila (5 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (4 commits)")

---

Tags

php rules engine

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Psalm

Type Coverage Yes

### Embed Badge

![Health badge](/badges/rogervila-php-simple-rules-engine/health.svg)

```
[![Health](https://phpackages.com/badges/rogervila-php-simple-rules-engine/health.svg)](https://phpackages.com/packages/rogervila-php-simple-rules-engine)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
