【问题标题】:How can I evaluate a math expression containing constants?如何评估包含常量的数学表达式?
【发布时间】:2016-03-27 16:47:55
【问题描述】:

如何在 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() 的实际常量?

【问题讨论】:

  • 不是重复的。请在标记为重复之前检查问题。 PHP error_reporting 对待它的值不同于重复的问题。
  • 如果我设置 $reporting_val = "E_ALL ^ E_WARNING";会有问题。也适用于将 var 设置为 0。
  • 好吧,如果您还想解析运算,那么您想要转换所有常量并使用所有位和数学运算符解析数学表达式。
  • @Izzy004 这种方法有什么用处?大多数应用程序通常在它们的引导过程中设置错误报告级别并且从不更改它。
  • @axiac 我正在尝试完成允许从自定义配置文件设置错误报告。文件由init引入并解析。长话短说,为了方便起见,我想在此文件中定义来自 w/i 的错误报告,因为当前设置允许每个应用程序有多个配置。允许一种有效的方法即时更改此类参数是有帮助的。希望我已经解释清楚了。这是一个复杂的应用程序,很难解释整个基础架构。

标签: php string expression constants


【解决方案1】:

说明

因此,既然您想使用带有 error constants 的数学表达式来表示 error_reporting(),那么您已经准备好表达式并对其进行评估。

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

  1. mathExpression 来评估你的数学表达式。

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

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

【讨论】:

  • 你我的朋友,是个天才。感谢您抽出时间提供帮助。
【解决方案2】:

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

解决方案 #1

我认为您不需要E_* 常量的所有可能组合。我会确定一些要使用的组合(例如E_ALLE_ALL &amp; ~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])。

【讨论】:

    猜你喜欢
    • 2012-01-14
    • 2012-07-05
    • 1970-01-01
    • 1970-01-01
    • 2010-12-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多