用PHP中的字符串公式评估数据集


9

我受命更新应用程序中的某些条件。我有一个要评估的数据集,并且已按照以下方式在应用程序中进行了硬编码:

$arr = array(
'a' => 'apple',
'b' => 'orange',
'c' => 1,
'd' => 2,
'e' => 5,
'f' => 'green',
'g' => 'red',
'h' => 'yellow',
)

$res1 = ($arr['a'] == 'apple') ? TRUE : FALSE;
$res2 = (($arr['b'] == $arr['f']) && ($arr['c'] < $arr['d']) ? TRUE : FALSE;
$res3 = (($arr['e'] == '5') && $res2) ?TRUE : FALSE;

等等...

在许多地方维护都是一场噩梦。

我本质上在寻找的是通过某种方式传递查询字符串以评估数据。首先,可以将一个简单的公式定义为数组

$formula = ['a', '=', 'apple'];

function query($formula, $arr) {
    switch ($formula[1]) {
        case '=':
            return ($arr[$formula[0]] == $formula[2]);
        case '!=':
            return ($arr[$formula[0]]!= $formula[2]);
        case '>':
            return ($arr[$formula[0]] > $formula[2]);
        case '<':
            return ($arr[$formula[0]] == $formula[2]);
    }
}

然后可以扩展并递归调用

$formula = [['a','=','apple'], 'AND', ['e','<','10']]

但我本质上在寻找的是将公式存储为字符串,例如:

"((([a]="orange") OR ([c]<"4")) AND ([g]="red"))"

其中[]将标识数组键

或者像在Excel中一样

"AND(OR(IF('a'='orange'),IF('c'<4)),IF('g'='red'))"

有没有干净的解决方案可以做到这一点?我有一个想法,也许将来会为它建立整个库。

我不想每次都在代码中添加新条件。它们已经遍及整个应用程序。最好将其存储在配置中,并在一个位置进行扩展或修改。

任何帮助,不胜感激。


1
编写评估程序是一项复杂的任务,但是您可以看看如何将ircmaxell对这个问题的答案扩展到处理和/或字符串。或查看类似PHPExcel
Mark Ba​​ker,

1
我猜一个“干净”的解决方案是建立一个具有不同功能的类,并将其包含在多个文件中。为了将代码存储为字符串并在以后进行评估,PHP提供了eval()

1
谢谢@MarkBaker,我可能会看看这些。并非我要找的你。我真的不想使用eval(),这可能太危险了,因为这些公式将由用户使用。这应该更加简单。
Pawel Jankowski 2015年

3
注意创建“内部平台效果”。到目前为止,很难想象您会节省很多代码。您可能不喜欢所有PHP的语法,但这是任何PHP开发人员(或C ++或Java开发人员)都可以理解的标准。因此,尽管尝试这似乎很有趣,但最好先在较小规模的副项目上进行试验。如果它在那里工作,则考虑将其滚动到大项目中。
John Doe 2015年

1
RPN评估程序将是编写和维护更简单的任务。它非常强大,可以减少出错的几率。从语言角度来看,它对用户的友好程度较低。
Scara95

Answers:


1

因此,这只是快速解决方案,但现在对我有效。

$arr = array('a' => 'red','b' => 'blue');

$formula = ['[a]', '=', 'red'];

如果公式中有[a],它将被视为数组键。

function query($formula, $arr) {

    $query_operator=$formula[1];

    if (is_array($formula[0])) {
        //recursive call
        $query_left = query($formula[0], $arr);
    } else {
        //extracting string between brackets
        preg_match("/\[([^\]]*)\]/", $formula[0], $match);
        $query_left = $match ? $arr[($match[1])] : $formula[0];
    }

    if (is_array($formula[2])) {
        //recursive call
        $query_right = query($formula[2], $arr);
    } else {
        //extracting string between brackets
        preg_match("/\[([^\]]*)\]/", $formula[2], $match);
        $query_right = $match ? $arr[($match[1])] : $formula[2];
    }


    switch ($query_operator) {
        case '=':
            return ($query_left == $query_right);
        case '!=':
            return ($query_left != $query_right);
        case '>':
            return ($query_left > $query_right);
        case '<':
            return ($query_left == $query_right);
        case 'AND':
            return ($query_left && $query_right);
        case 'OR':
            return ($query_left || $query_right);
    }
}

在此解决方案中,它将使用以下公式:

$formula = [['[a]', '=', 'red'], 'AND', ['[b]', '=', 'blue']];

这不是我想要的,但是可以完成工作,也不那么糟糕(我希望如此)。它需要一些输入检查和错误处理,但这只是一个例子。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.