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

时间:2016-03-27 16:47:56

标签: php string expression 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()的实际常量?

2 个答案:

答案 0 :(得分:1)

解释

因此,您希望将error constants的数学表达式用于error_reporting(),您已准备好表达式并对其进行评估。

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

  1. 用于评估数学表达式的课程mathExpression

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

  3. mathExpression类只需要一个数学表达式并删除除数字,数学和位操作符之外的所有内容。然后它只计算它并返回结果。

    convertErrorConstants()函数使用preg_replace_callback()搜索所有E_*,并检查是否存在使用该名称定义的常量。如果是,我们使用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 :(得分:0)

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

解决方案#1

我认为您不需要E_*常量的所有可能组合。我将确定一些要使用的组合(fe 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,
);

&#34;解析&#34;代码:

// 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])。