プログラミングしていてこんな経験ありませんか?
機能自体は単純なのに、判定条件だけがどんどん増えていく。
ユーザーの状態、設定項目、商品属性、会員レベル...
無数の if/else が絡み合い、コードが混沌としていく。
一箇所修正するだけで、他の部分への影響が心配になる。
私も同じ状況に直面しました。最初は我慢していましたが、ついに決断しました:シンプルなルールエンジンを自作して、これらの複合判定を専門に処理しようと。
こうして生まれたのが:hejunjie/simple-rule-engine
このルールエンジンで何ができる?
要約すると:
軽量で使いやすい PHP ルールエンジン。複数条件の組み合わせ、動的ルール実行をサポートし、ビジネスルール判定やデータ検証などのシーンに適しています。
プロジェクトのこうした場面で活躍します:
- 複雑なビジネスロジックの多条件判定(例:ユーザーがキャンペーン条件を満たしているか)
- データ保存前のルール検証
- カスタムロジックの設定化・構造化
- if 地獄から抜け出して整理整頓したい場合 😅
なぜ作ったのか?
実際のビジネスでは、多くの判定ロジックを「複数のフィールド + いくつかのルール + 条件の組み合わせ」として表現できます。
従来はこのように書いていました:
if (
$profile['status'] === 'active' &&
$profile['age'] >= 18 &&
in_array($profile['permission'], ['admin', 'editor'])
) {
// 処理...
}
今ではこう書けます:
// ルール定義
$criteria = [
new Criterion('age', '>=', 18, '年齢は18歳以上必要'),
new Criterion('status', '==', 'active', 'ステータスはactive必須'),
new Criterion('permission', 'in', ['admin', 'editor'], '権限が必要'),
];
// 評価実行
$result = RuleEngine::assess($criteria, $profile, 'AND'); // true/falseを返す
// 詳細評価情報(各ルールの実行状況取得)
$report = RuleEngine::assessWithDetails($criteria, $profile);
/*
返却例:
[
['description' => '年齢は18歳以上必要', 'passed' => true],
['description' => 'ステータスはactive必須', 'passed' => true],
['description' => '権限が必要', 'passed' => true]
]
*/
すっきりしませんか?さらに、ルールをデータベースに保存すれば「ビジネス判定の設定化」も実現できます。
プロジェクトの特徴
- 軽量でシンプル:依存関係なし、フレームワーク非依存、数行で使える
- ファクトリ登録機能:独自のオペレーターを登録して拡張可能
- 標準オペレーター搭載:一般的なオペレーターを多数サポート(記事末尾のリスト参照)
- 組み合わせ可能:AND/OR関係の組み合わせをサポート、複数ルールセットの拡張が容易
導入方法
composer require hejunjie/simple-rule-engine
️ サンプルコード
use Hejunjie\SimpleRuleEngine\Criterion;
use Hejunjie\SimpleRuleEngine\RuleEngine;
// ルールセット定義
$criteria = [
new Criterion('age', '>=', 18, '年齢は18歳以上必要'),
new Criterion('status', '==', 'active', 'ステータスはactive必須'),
new Criterion('permission', 'in', ['admin', 'editor'], '権限が必要'),
];
$target = ['age' => 20, 'nation' => 'Japan'];
// 全ルールのパス判定
if (RuleEngine::assess($criteria, $target, 'AND')) {
echo 'ルールを満たしています';
}
// 各ルールの詳細結果
foreach (RuleEngine::assessWithDetails($criteria, $target) as $item) {
echo $item['description'] . ':' . ($item['passed'] ? '✅ 合格' : '❌ 不合格') . PHP_EOL;
}
カスタムオペレーター
独自の判定ロジックを実装し、任意のオペレーターを定義してルールに組み込めます。
OperatorInterface を実装し、OperatorFactory 経由で登録するだけ:
use Hejunjie\SimpleRuleEngine\Interface\OperatorInterface;
use Hejunjie\SimpleRuleEngine\OperatorFactory;
class CustomOperator implements OperatorInterface
{
/**
* 評価メソッド
*
* @param mixed $inputValue 入力データ
* @param mixed $compareValue 比較データ
*
* @return bool
*/
public function evaluate(mixed $inputValue, mixed $compareValue): bool
{
// TODO: 判定ロジックを実装
}
/**
* オペレーター名
*
* @return string
*/
public function name(): string
{
return 'custom';
}
}
// カスタムオペレーター custom を登録
$factory = OperatorFactory::getInstance();
$factory->register(new CustomOperator());
// ルール定義で custom を使用可能
$criteria = [
new Criterion('field', 'custom', 'value', 'カスタムルール説明'),
// ...
// ...
];
// RuleEngine::assess($criteria, $target, 'AND')
// RuleEngine::assessWithDetails($criteria, $target)
標準オペレーター一覧
オペレーター説明補足==等しいなし!=等しくないなし>より大きいなし>=以上なし<より小さいなし<=以下なし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 をお待ちしています。一緒に改善していきましょう 🙌
役立つと思っていただけたら、いいねいただけると更新の励みになります~