Auswertung des Datensatzes mit einer String-Formel in PHP

9

Ich wurde beauftragt, einige Bedingungen in einer Anwendung zu aktualisieren. Ich habe einen Datensatz, der ausgewertet werden soll, und er wurde in der Anwendung folgendermaßen fest codiert:

$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;

und so weiter...

Es ist ein Albtraum, an vielen Orten aufrechtzuerhalten.

Was ich im Wesentlichen suche, ist eine Möglichkeit, eine Abfragezeichenfolge zu übergeben, um Daten auszuwerten. Zu Beginn könnte eine einfache Formel als Array definiert werden

$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]);
    }
}

Dies könnte dann erweitert und rekursiv aufgerufen werden

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

aber was ich im Wesentlichen suche, ist, Formeln aa Zeichenfolge zu speichern, wie:

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

wo [] würde Array-Schlüssel identifizieren

oder vielleicht so etwas wie in Excel

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

Gibt es dafür eine saubere Lösung? Ich habe eine Idee, wie ich vielleicht in Zukunft eine ganze Bibliothek dafür bauen kann.

Ich möchte dem Code nicht jedes Mal neue Bedingungen hinzufügen. Sie sind bereits überall in der Anwendung. Es ist besser, es in der Konfiguration zu speichern und an einem Ort zu erweitern oder zu ändern.

Jede Hilfe sehr geschätzt.

Pawel Jankowski
quelle
1
Das Schreiben eines Evaluators ist eine komplexe Aufgabe, aber Sie können auch die Antwort von ircmaxell auf diese Frage erweitern , um auch und / oder Zeichenfolgen zu behandeln. oder schauen Sie sich die Berechnungs-Engine in so etwas wie PHPExcel
Mark Baker
1
Ich denke, eine "saubere" Lösung wäre, eine Klasse mit verschiedenen Funktionen einzurichten und in mehrere Dateien aufzunehmen. Um Code als Zeichenfolge zu speichern und später auszuwerten, bietet PHP an eval().
1
Vielen Dank an MarkBaker, ich könnte mir diese ansehen. Nicht genau das, wonach ich suche. Ich möchte eval () nicht wirklich verwenden, dies könnte zu gefährlich sein, da diese Formeln von Benutzern verwendet werden. Dies sollte kinderleichter sein.
Pawel Jankowski
3
Achten Sie darauf, dass Sie einen "Effekt für die innere Plattform" erzielen. Nach dem, was Sie uns bisher gezeigt haben, ist es schwer vorstellbar, dass Sie am Ende viele Codezeilen speichern würden. Möglicherweise bevorzugen Sie nicht die gesamte PHP-Syntax, aber es ist ein Standard, den jeder PHP-Entwickler (oder C ++ - oder Java-Entwickler) verstehen kann. Während es also Spaß macht, es zu versuchen, ist es vielleicht besser, zuerst mit einem kleineren Nebenprojekt zu experimentieren. Wenn es dort funktioniert, sollten Sie es in das große Projekt einbinden.
John Doe
1
Ein RPN-Evaluator wäre einfacher zu schreiben und zu warten. Es ist ziemlich mächtig und es gibt weniger Dinge, die man falsch machen kann. Es ist weniger benutzerfreundlich als ein Sprachgedanke.
Scara95

Antworten:

1

Das ist also nur eine schnelle Lösung, funktioniert aber gerade für mich.

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

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

Wenn die Formel [a] enthält, wird sie als Array-Schlüssel behandelt.

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);
    }
}

In dieser Lösung funktioniert es mit folgenden Formeln:

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

Es ist nicht genau das, was ich wollte, aber es macht den Job und ist nicht so schrecklich (hoffe ich). Es bedarf einiger Eingangsüberprüfungen und Fehlerbehandlungen, dies ist jedoch nur ein Beispiel.

Pawel Jankowski
quelle