Оцінювання набору даних за допомогою рядкової формули в 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']]

але те, що я по суті шукаю, - це зберігати формули aa string, як-от:

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

де [] ідентифікував би ключі масиву

а може щось на зразок в Excel

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

Чи є чисте рішення для цього? У мене є ідея, як створити для цього цілу бібліотеку, можливо, в майбутньому.

Я не хочу кожного разу додавати нові умови до коду. Вони вже в усьому застосуванні. Було б краще зберігати його в конфігурації та розширювати або змінювати в одному місці.

Будь-яка допомога дуже цінується.


1
Написання оцінювача є складним завданням, але ви можете поглянути на розширення відповіді ircmaxell на це питання для обробки та / або та рядків; або подивіться на механізм обчислення приблизно як PHPExcel
Марк Бейкер

1
Я думаю, що "чистим" рішенням було б створити клас з різними функціями та включити його до кількох файлів. Щоб зберігати код як рядок та оцінювати його пізніше, PHP пропонує eval().

1
Дякую @MarkBaker, я можу поглянути на них. Не зовсім те, що я тебе шукаю. Я не хочу дуже використовувати eval (), це може бути занадто небезпечно, оскільки ті формули будуть використовуватися користувачами. Це має бути більш надійним.
Pawel Jankowski

3
Слідкуйте за тим, щоб створити "ефект внутрішньої платформи". Важко уявити з того, що ви нам показали до цих пір, що ви в кінцевому підсумку збережете багато рядків коду. Ви можете не віддавати перевагу всім синтаксисам PHP, але це стандарт, який може зрозуміти будь-який розробник PHP (або C ++ або Java-розробник). Тому, хоча це здається цікавою справою, можливо, краще спершу експериментувати з цим на меншому масштабі побічного проекту. Якщо він працює там, то подумайте про те, щоб перетворити його на великий проект.
Джон Доу

1
Оцінювач RPN був би простішим завданням для написання та обслуговування. Він досить потужний і є менше речей, в яких можна помилитися. Він менш зручний для користувачів, як мовна думка.
Scara95

Відповіді:


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']];

Це не зовсім те, що я хотів, але робить роботу, і це не так страшно (сподіваюся). Він потребує певної перевірки входу та обробки помилок, але це лише приклад.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.