如何评估包含常量的数学表达式?
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 个不同的部分。
classmathExpression
计算你的数学表达式。
我们使用函数 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_ALL
、E_ALL & ~E_NOTICE
、0
等)并定义要用于这些组合的值配置文件。
$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]
未设置)。
如何将 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 个不同的部分。
class
mathExpression
计算你的数学表达式。我们使用函数
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_ALL
、E_ALL & ~E_NOTICE
、0
等)并定义要用于这些组合的值配置文件。
$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]
未设置)。