本文目录导读:

在 PHP 中实现 DSL(领域特定语言)规则,主要有以下几种方式:
方法链式调用(Fluent Interface)
这是最常用的方式,通过方法链构建规则。
<?php
class RuleBuilder {
private $rules = [];
private $currentField = '';
private $currentOperator = '';
private $currentValue = null;
public function field($field) {
$this->currentField = $field;
return $this;
}
public function equals($value) {
$this->currentOperator = '=';
$this->currentValue = $value;
return $this->addRule();
}
public function greaterThan($value) {
$this->currentOperator = '>';
$this->currentValue = $value;
return $this->addRule();
}
public function lessThan($value) {
$this->currentOperator = '<';
$this->currentValue = $value;
return $this->addRule();
}
public function addRule() {
$this->rules[] = [
'field' => $this->currentField,
'operator' => $this->currentOperator,
'value' => $this->currentValue
];
return $this;
}
public function getRules() {
return $this->rules;
}
}
// 使用示例
$builder = new RuleBuilder();
$rules = $builder
->field('age')->greaterThan(18)
->field('status')->equals('active')
->field('score')->lessThan(100)
->getRules();
print_r($rules);
使用匿名函数或闭包
<?php
class RuleEngine {
private $rules = [];
public function when(callable $condition, callable $action) {
$this->rules[] = [
'condition' => $condition,
'action' => $action
];
return $this;
}
public function evaluate($data) {
foreach ($this->rules as $rule) {
if ($rule['condition']($data)) {
return $rule['action']($data);
}
}
return null;
}
}
// 使用示例
$engine = new RuleEngine();
$result = $engine
->when(
fn($user) => $user['age'] >= 18 && $user['status'] === 'active',
fn($user) => "已成年且活跃用户"
)
->when(
fn($user) => $user['age'] < 18,
fn($user) => "未成年用户"
)
->evaluate(['age' => 25, 'status' => 'active']);
echo $result;
使用数组配置 DSL
<?php
class ArrayRuleDSL {
private $rules = [];
public function addRule(array $rule) {
$this->rules[] = $rule;
return $this;
}
public function evaluate($data) {
foreach ($this->rules as $rule) {
if ($this->matches($rule['condition'], $data)) {
return $rule['result'];
}
}
return null;
}
private function matches($condition, $data) {
foreach ($condition as $field => $constraint) {
if (is_array($constraint)) {
foreach ($constraint as $op => $value) {
if (!$this->applyOperator($op, $data[$field] ?? null, $value)) {
return false;
}
}
} elseif ($data[$field] !== $constraint) {
return false;
}
}
return true;
}
private function applyOperator($operator, $actual, $expected) {
switch ($operator) {
case 'gt': return $actual > $expected;
case 'gte': return $actual >= $expected;
case 'lt': return $actual < $expected;
case 'lte': return $actual <= $expected;
case 'eq': return $actual === $expected;
case 'neq': return $actual !== $expected;
case 'in': return in_array($actual, $expected);
case 'between': return $actual >= $expected[0] && $actual <= $expected[1];
default: return false;
}
}
}
// 使用示例
$ruleDSL = new ArrayRuleDSL();
$ruleDSL
->addRule([
'condition' => [
'age' => ['gte' => 18, 'lte' => 65],
'status' => 'active'
],
'result' => '符合资质的用户'
])
->addRule([
'condition' => [
'age' => ['lt' => 18]
],
'result' => '未成年用户'
]);
echo $ruleDSL->evaluate(['age' => 25, 'status' => 'active']);
使用解析器模式(复杂 DSL)
<?php
class DSLParser {
private $data = [];
public function parse($expression) {
// 解析类似:"IF age > 18 AND status = 'active' THEN '符合条件'"
$expression = trim($expression);
if (preg_match('/IF (.+?) THEN (.+)/i', $expression, $matches)) {
$condition = $this->parseCondition($matches[1]);
$result = $matches[2];
if ($this->evaluateCondition($condition)) {
return $result;
}
}
return null;
}
private function parseCondition($condition) {
// 支持 AND/OR
$parts = preg_split('/\s+(AND|OR)\s+/i', $condition, -1, PREG_SPLIT_DELIM_CAPTURE);
$groups = [];
$currentGroup = [];
foreach ($parts as $part) {
if (strtoupper($part) === 'AND' || strtoupper($part) === 'OR') {
$currentGroup['operator'] = strtoupper($part);
} else {
$currentGroup['conditions'][] = $this->parseSimpleCondition($part);
}
}
return $currentGroup;
}
private function parseSimpleCondition($condition) {
// 解析:field > value, field = 'value', field BETWEEN x AND y
if (preg_match('/^(.+?)\s*(>=|<=|==|!=|>|<|=)\s*(.+)$/', trim($condition), $matches)) {
return [
'field' => trim($matches[1]),
'operator' => $matches[2],
'value' => $this->parseValue($matches[3])
];
}
return null;
}
private function parseValue($value) {
$value = trim($value);
if (preg_match('/^\'(.+)\'$/', $value, $matches)) {
return $matches[1];
}
if (is_numeric($value)) {
return (float)$value;
}
return $value;
}
private function evaluateCondition($condition) {
if (isset($condition['operator'])) {
$result = false;
foreach ($condition['conditions'] as $subCondition) {
$subResult = $this->evaluateSimple($subCondition);
if ($condition['operator'] === 'AND') {
$result = $result && $subResult;
} else {
$result = $result || $subResult;
}
}
return $result;
}
return $this->evaluateSimple($condition['conditions'][0]);
}
private function evaluateSimple($condition) {
$fieldValue = $this->data[$condition['field']] ?? null;
switch ($condition['operator']) {
case '>': return $fieldValue > $condition['value'];
case '<': return $fieldValue < $condition['value'];
case '>=': return $fieldValue >= $condition['value'];
case '<=': return $fieldValue <= $condition['value'];
case '=': return $fieldValue == $condition['value'];
case '==': return $fieldValue === $condition['value'];
case '!=': return $fieldValue != $condition['value'];
default: return false;
}
}
public function setData($data) {
$this->data = $data;
return $this;
}
}
// 使用示例
$parser = new DSLParser();
$result = $parser
->setData(['age' => 25, 'status' => 'active'])
->parse("IF age >= 18 AND status = 'active' THEN '资格通过'");
echo $result;
使用现有库
也可以使用一些现成的 PHP DSL 库:
使用 symfony/expression-language
composer require symfony/expression-language
<?php
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
$language = new ExpressionLanguage();
$data = ['age' => 25, 'status' => 'active'];
// 评估表达式
$result = $language->evaluate(
"age >= 18 and status == 'active'",
$data
);
echo $result ? '通过' : '不通过';
使用 hanson/expression
composer require hanson/expression
<?php
use Hanson\Expression\Expression;
$expression = new Expression();
$result = $expression->evaluate("age > 18 && status = 'active'", ['age' => 20, 'status' => 'active']);
选择建议
- 简单规则:使用方法链式调用或数组配置
- 复杂业务规则:使用闭包组合
- 需要动态配置:使用表达式解析器
- 生产环境:考虑使用成熟的库(如 symfony/expression-language)
这些方式可以根据你的具体需求选择或组合使用,DSL 的核心目的是让规则更加可读、可维护,降低代码耦合度。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播