xakepehok/expression-executor

表达式执行器,允许实现特定领域语言

0.5.2 2024-06-06 08:40 UTC

This package is auto-updated.

Last update: 2024-09-06 09:10:07 UTC


README

表达式执行器,允许实现特定领域语言。此库不包含任何已实现的运算符或函数。它只是一个框架,允许您构建自己的表达式特定领域语言,包括任何函数、运算符和类型系统。

您可以定义自己的运算符、函数和变量。例如,您想要计算/执行以下表达式

MIN(5, 10.5) + NUMBER_OF_DAY(year: "2019", month: "01", day: "20") + PI * {{VARIABLE}} + ((-2) + 2.5) * 2

在上面的示例中

  • MINNUMBER_OF_DAY - 函数
  • {{VARIABLE}} - 变量
  • PI - 用户定义常量的语法(例如,您可以定义 TRUE、FALSE 和 NULL 常量)
  • +* - 运算符
  • "5""10""2019" - 双引号中的字符串
  • 510.5(-2)2.52 - 作为整数/浮点数,但负值应加括号

此外,它还支持数组和布尔逻辑,如下所示

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

与类似产品的区别