การประเมินชุดข้อมูลด้วยสูตรสตริงใน 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 Baker

1
ฉันเดาโซลูชัน "สะอาด" จะตั้งชั้นเรียนด้วยฟังก์ชั่นที่แตกต่างกันและรวมไว้ในหลายไฟล์ ในการจัดเก็บรหัสเป็นสตริงและประเมินผลภายหลัง PHP eval()ข้อเสนอ

1
ขอบคุณ @MarkBaker ฉันอาจได้ดูสิ่งเหล่านั้น ไม่ใช่สิ่งที่ฉันกำลังมองหา ฉันไม่ต้องการใช้ eval () นี่อาจเป็นอันตรายเกินไปเนื่องจากสูตรเหล่านั้นจะถูกใช้โดยผู้ใช้ นี่น่าจะเข้าใจผิดได้มากกว่านี้
Pawel Jankowski

3
ระวังการสร้าง "เอฟเฟกต์ด้านในแพลตฟอร์ม" มันยากที่จะจินตนาการจากสิ่งที่คุณแสดงให้เราเห็นว่าคุณจะได้รับการบันทึกโค้ดหลายบรรทัด คุณอาจไม่ชอบไวยากรณ์ของ PHP ทั้งหมด แต่เป็นมาตรฐานที่นักพัฒนา PHP (หรือ C ++ หรือผู้พัฒนา Java) สามารถเข้าใจได้ ดังนั้นในขณะนี้ดูเหมือนจะเป็นเรื่องสนุกที่จะลองมันอาจเป็นการดีกว่าที่จะทดสอบกับมันก่อนในโครงการขนาดเล็ก หากใช้งานได้ให้ลองนำไปใช้ในโครงการใหญ่
John Doe

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

มันไม่ตรงกับที่ฉันต้องการ แต่ทำงานและไม่แย่มาก (ฉันหวังว่า) ต้องมีการตรวจสอบอินพุตและการจัดการข้อผิดพลาด แต่นี่เป็นเพียงตัวอย่าง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.