xakepehok / expression-executor
表达式执行器,允许实现特定领域语言
0.5.2
2024-06-06 08:40 UTC
Requires
- php: >=7.4
- ext-mbstring: *
Requires (Dev)
- phpunit/phpunit: ^9.0
README
表达式执行器,允许实现特定领域语言。此库不包含任何已实现的运算符或函数。它只是一个框架,允许您构建自己的表达式特定领域语言,包括任何函数、运算符和类型系统。
您可以定义自己的运算符、函数和变量。例如,您想要计算/执行以下表达式
MIN(5, 10.5) + NUMBER_OF_DAY(year: "2019", month: "01", day: "20") + PI * {{VARIABLE}} + ((-2) + 2.5) * 2
在上面的示例中
MIN
和NUMBER_OF_DAY
- 函数{{VARIABLE}}
- 变量PI
- 用户定义常量的语法(例如,您可以定义 TRUE、FALSE 和 NULL 常量)+
和*
- 运算符"5"
、"10"
、"2019"
- 双引号中的字符串5
、10.5
、(-2)
、2.5
、2
- 作为整数/浮点数,但负值应加括号
此外,它还支持数组和布尔逻辑,如下所示
("HELLO" IN ["HELLO", "WORLD"]) && (10 IN [2+2, 3+3, 5+5, "string here"])
其中
["HELLO", "WORLD"]
- 字符串数组[2+2, 3+3, 5+5, "string here"]
- 混合整数和字符串的数组IN
- 运算符,检查数组是否包含值&&
- 逻辑运算符 "与"
安装
composer require xakepehok/expression-executor
使用方法
为了计算/执行上述表达式,您需要定义这些函数、运算符和值
MIN()
<?php class MinFunction implements \XAKEPEHOK\ExpressionExecutor\FunctionInterface { public function getName(): string { return 'MIN'; } public function execute(array $arguments, array $context) { return min($arguments); } }
NUMBER_OF_DAY()
<?php class NumberOfDayFunction implements \XAKEPEHOK\ExpressionExecutor\FunctionInterface { public function getName(): string { return 'NUMBER_OF_DAY'; } public function execute(array $arguments, array $context) { $year = $arguments['year'] ?? ($arguments[0] ?? null); $month = $arguments['month'] ?? ($arguments[1] ?? null); $day = $arguments['day'] ?? ($arguments[2] ?? null); if ($year === null || $month === null || $day === null) { throw new \XAKEPEHOK\ExpressionExecutor\Exceptions\FunctionException('Arguments error'); } return date('N', strtotime("{$year}-{$month}-{$day}")); } }
+
运算符
<?php class PlusOperator implements \XAKEPEHOK\ExpressionExecutor\OperatorInterface { public function operator() : string { return '+'; } /** * Custom integer priority value. For example, for "+" it can be 1, for "*" it can be 2 * @return int */ public function priority() : int { return 1; } public function execute($leftOperand, $rightOperand, array $context) { return $leftOperand + $rightOperand; } }
*
运算符
<?php class MultiplyOperator implements \XAKEPEHOK\ExpressionExecutor\OperatorInterface { public function operator() : string { return '*'; } /** * Custom integer priority value. For example, for "+" it can be 1, for "*" it can be 2 * @return int */ public function priority() : int { return 2; } public function execute($leftOperand, $rightOperand, array $context) { return $leftOperand * $rightOperand; } }
IN
运算符
<?php class InOperator implements \XAKEPEHOK\ExpressionExecutor\OperatorInterface { public function operator() : string { return 'IN'; } /** * Custom integer priority value. For example, for "+" it can be 1, for "*" it can be 2 * @return int */ public function priority() : int { return 1; } public function execute($leftOperand, $rightOperand, array $context) { return in_array($leftOperand, $rightOperand, true); } }
&&
运算符
<?php class AndOperator implements \XAKEPEHOK\ExpressionExecutor\OperatorInterface { public function operator() : string { return '&&'; } /** * Custom integer priority value. For example, for "+" it can be 1, for "*" it can be 2 * @return int */ public function priority() : int { return 1; } public function execute($leftOperand, $rightOperand, array $context) { return $leftOperand && $rightOperand; } }
创建执行器实例
<?php $executor = new \XAKEPEHOK\ExpressionExecutor\Executor( [new MinFunction(), new NumberOfDayFunction()], [new PlusOperator(), new MultiplyOperator(), new InOperator(), new AndOperator()], function ($name, array $context) { $vars = [ 'VARIABLE' => 10, 'CONTEXT.VALUE' => $context['value'], ]; return $vars[$name]; }, ['PI' => 3.14] ); //And simply execute our expression $result_1 = $executor->execute('MIN(5, 10.5) + NUMBER_OF_DAY(year: "2019", month: "01", day: "20") + PI * {{VARIABLE}} + ((-2) + 2.5) * 2'); $result_2 = $executor->execute('("HELLO" IN ["HELLO", "WORLD"]) && (10 IN [2+2, 3+3, 5+5, "string here"])');
特性
- 它很安全。没有
eval()
- 执行器可以返回和处理任何类型的数据。所有类型检查和处理都应该在您的类(函数和运算符)中实现
- 字符串参数支持转义双引号,例如
"My name is \"Timur\""
- 函数可以接受任何数量的参数(您可以在函数体中通过异常限制)
- 函数参数可以是命名的
NUMBER_OF_DAY(year: "2019", month: "01", day: "20")
和未命名的 NUMBER_OF_DAY("2019", "01", "20"),但不能混合使用 - 函数参数可以是字符串、数字、变量、常量、其他函数的结果和任何表达式
- 您可以将上下文(任何常见数据作为数组)作为第二个参数传递给
execute()
方法。上下文将被传递给可调用的函数、运算符和变量 - 使用括号
(2 + 2) * 2
来表示优先级 - 使用括号表示负数,例如
(-1)
、(-1.2)
- 您可以实现任何运算符,例如
>
、>=
、<
、<=
和您想要的任何其他运算符
有关更多示例,请参阅 ExecutorTest.php
与类似产品的区别
- https://symfony.com.cn/doc/current/components/expression_language.html - 优秀的 symfony 表达式组件,但无法覆盖任何内置运算符的逻辑,也无法使用自己的严格类型系统。唯一扩展的方式是定义自己的函数
- https://github.com/NeonXP/MathExecutor - 优秀的数学表达式计算器,具有用户定义的运算符和函数,但同样无法使用自己的严格类型系统。例如,您无法执行类似于 Datetime - Datetime (保留类型) 的操作