如何评估包含常量的数学表达式?

How can I evaluate a math expression containing constants?

如何将 PHP 中的字符串用作 PHP 值?

以下是我要实现的目标:

$reporting_val = "E_ALL";  //Could also look like this "E_ALL ^ E_WARNING"
error_reporting($reporting_val);

我想使用字符串 E_ALL 作为 error_reporting() 的常量。

我知道可以像这样将字符串传递给 PHP 中的变量名:

${$reporting_val} = true;

有没有办法使用包含常量的字符串作为 error_reporting() 的实际常量?

说明

因此,由于您想将数学表达式与 error constants for error_reporting() 一起使用,因此您已经准备好表达式并对其求值。

因此我们在这里有 2 个不同的部分。

  1. classmathExpression 计算你的数学表达式。

  2. 我们使用函数 convertErrorConstants() 将所有带有前缀 E_* 的错误常量转换为整数。

mathExpression class 简单地采用数学表达式并删除除数字、数学和位运算符之外的所有内容。然后它只是计算它并 returns 返回结果。

convertErrorConstants() 函数搜索所有 E_*preg_replace_callback() and checks if there is a constant defined with that name. If yes we return the value from it with constant()

代码

<?php

    class mathExpression {

        public $expression = NULL;


        public function __construct($expression = NULL){
            $this->expression = is_null($expression) ? NULL : $expression;
        }

        public function calculate($expression = NULL){

            $this->expression = !is_null($expression) ? $expression : $this->expression;

            if(is_null($this->expression))
                throw new Exception("No expression set");         

            $this->expression = str_replace([",", " "], [".", ""], $this->expression);
            $this->expression = preg_replace("/[^\d.+*%^|&<>\/()-]/", "", $this->expression);


            $result = $this->compute($this->expression);
            return $result;               

        }

        private function compute($input){
            $compute = create_function("", "return " . $input . ";");
            return 0 + $compute();
        }

        public function setExpression($expression){
            $this->expression = $expression;
        }

    }



    function convertErrorConstants($input){
        $output = preg_replace_callback("/(E_[a-zA-Z_]+)/", function($m){
            if(defined($m[1]))
                return constant($m[1]);
            return $m[0];
        }, $input);

        return $output;
    }


    $str = "E_ALL ^ E_WARNING";

    $str = convertErrorConstants($str);

    $exp = new mathExpression();
    $exp->setExpression($str);
    $result = $exp->calculate();

    var_dump($result);

?>

输出:

int(32765)  //E_ALL ^ E_WARNING -> 32767 ^ 2 -> 32765

//32767 ^ 2

//0111 1111 1111 1111 ^  //32767
//                 11    //    2
//----------------------
//0111 1111 1111 1100    = 32765

两个易于实施的解决方案。

解决方案 #1

我认为您不需要 E_* 常量的所有可能组合。我会确定一些要使用的组合(f.e、E_ALLE_ALL & ~E_NOTICE0 等)并定义要用于这些组合的值配置文件。

$errorLevels = array(
    'all'         => E_ALL,
    'almost-all'  => E_ALL & ~E_NOTICE,
    'errors-only' => E_ALL & ~(E_NOTICE | E_WARNING),
    // ...
    'nothing'     => 0,
);

在配置文件中使用 $errorLevels 的键,在代码中查找 $errorLevels 中的键并找到要传递给 error_reporting() 的值。

解决方案 #2

一个更灵活的选项是在配置文件中有两个条目:一个用于要包含的级别,另一个用于要排除的级别(当 E_ALL 在包含的级别列表中时很有用)。

在配置文件中:

errorLevelsPlus=all
errorLevelsMinus=notice,warning

代码中:

// Put all the E_* error levels here
$errorLevels = array(
    'all'     => E_ALL,
    'error'   => E_ERROR,
    'warning' => E_WARNING,
    'notice'  => E_NOTICE,
    // ... put all the missing E_* values here
    'none'    => 0,
);

“解析”代码:

// Read the configuration values (comma separated strings)
$levelsPlus  = get_config('errorLevelsPlus');
$levelsMinus = get_config('errorLevelsMinus');

// Compute the combination
$value = 0;
// Add the levels to include
foreach (explode(',', $levelsPlus) as $level) {
    if (isset($errorLevels[$level])) {
        $value |= $errorLevels[$level];
    }
}
// Subtract the levels to exclude
foreach (explode(',', $levelsMinus) as $level) {
    if (isset($errorLevels[$level])) {
        $value &= ~$errorLevels[$level];
    }
}

您需要添加配置错误的处理(当您在配置文件中拼错单词时,f.e。并且$errorLevels[$level]未设置)。