Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Evaluate PHP logic stored in arrays

Objective

I'm trying to store complex comparisons as PHP arrays. I then want to read the array to evaluate a group of variables and return whether the statement is true or false.

Question

How can I store complex comparisons so that they can later be read and evaluate the variables present at the time? Is this the best way to accomplish this? Your help is GREATLY appreciated.

Example, English

If($source = 200 OR $source = 300) AND ($age < 10 OR $age > 60) THAN return true Else return false

Notes: Variables can be any variable in the code, I used source and age as an example here. The nested arrays can be deeper or flatter than the example.

Example, Code

$conditions = Array
(
[relation] => AND
[0] => Array
    (
        [relation] => OR
        [0] => Array
            (
                [var] => source
                [compare] => =
                [value] => 300
            )

        [1] => Array
            (
                [var] => source
                [compare] => =
                [value] => 300
            )

    )

[1] => Array
    (
        [relation] => OR
        [0] => Array
            (
                [var] => age
                [compare] => <
                [value] => 10
            )

        [1] => Array
            (
                [var] => age
                [compare] => >
                [value] => 60
            )

    )

)

SOLUTION

Based on the answer by @sam-grondahl Function can handle any nested logic you can throw at it. Accepts regex and numeric comparisons

$source = '300';
$age = '60';

$input_variables = array('source' => $source, 'age' => $age);

$conditions = array(
                'relation' => 'and',
                array(
                        'relation' => 'and',
                        array(
                              'var' => 'source',
                              'compare' => 'regex',
                              'value' => '(200|300)+'
                              ),
                        array(
                              'relation' => 'OR',
                                array(
                                      'var' => 'age',
                                      'compare' => '=',
                                      'value' => '59'
                                      ),
                                array(
                                      'var' => 'age',
                                      'compare' => '=',
                                      'value' => '60'
                                      )
                                      )
                      ),
                array(
                        'relation' => 'or',
                        array(
                              'var' => 'age',
                              'compare' => '<',
                              'value' => '10'                                 
                              ),
                        array(
                              'var' => 'age',
                              'compare' => '>=',
                              'value' => '60'
                              )
                      ),
                     array(
                              'var' => 'source',
                              'compare' => '=',
                              'value' => '300'
                              ),

                );


function evaluateConditions($condArray, $varablesArray){

if(!$condArray || !is_array($condArray)){throw new Exception('Missing Conditions Input Array');}
if(!$varablesArray || !is_array($varablesArray)){throw new Exception('Missing Variables Input Array');}

//PULL VARIABLES FROM ARRAY
foreach($varablesArray as $key_var => $value_var){
    ${$key_var} = $value_var;
}


///PROCESS THE ARRAY THAT CONTAINS THE COMPARISON ARRAY
if (!$condArray['relation']){

 //FORMAT COMPARE INPUT
 $condArray['compare'] = strtoupper(trim($condArray['compare']));
 $condArray['compare'] = preg_replace('/^=$/','==',$condArray['compare']);

 ///ACCEPTED COMPARE VALUES
 $accepted_compare_array = array('=','==','===','<>','!=','!==','>','>=','<','<=','REGEX');

 //VERIFY REQUIRED FIELDS ARE PRESENT
 if(!$condArray['var']){throw new Exception('Missing var');}
 if(!$condArray['compare']){throw new Exception('Missing compare');}
 if(!$condArray['value']){throw new Exception('Missing value');}

 //VERIFY ALL VALUES
 if($condArray['compare'] != 'REGEX' && !is_numeric($condArray['value'])){throw new Exception('Value is Not Numeric');}
 if(!in_array($condArray['compare'], $accepted_compare_array)){throw new Exception('Invalid Compare Value');}
 if(!preg_match("/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/",$condArray['var'])){throw new Exception('Invalid Var');}

 if($condArray['compare'] == 'REGEX'){
    $condArray['compare'] = preg_replace('/\//','\/',$condArray['compare']);
    $eval_str = 'if(preg_match("/'.$condArray['value'].'/i", $'.$condArray['var'].')){return 1;} else{return 0;}'; 
 }
 else{   
    $eval_str = 'if($'.$condArray['var'].' '.$condArray['compare'].' '.$condArray['value'].'){return 1;} else{return 0;}';
 }

 return eval($eval_str);

 }
else{

 $condArray['relation'] = strtoupper(trim($condArray['relation']));

 //VERIFY RELATION VALUE
 $accepted_relation_array = array('AND','OR');
 if(!in_array($condArray['relation'], $accepted_relation_array)){throw new Exception('Relation Invalid');}

 //VERIFY THAT AT LEAST TWO ARRAYS
 $array_count = 0;
 foreach($condArray as $condArray_var){
    if(is_array($condArray_var)){$array_count++;} 
 }

 if($array_count < 2){throw new Exception('Missing Comparison Array');}

 }



if (strtoupper($condArray['relation']) == 'OR') {
 unset($condArray['relation']);

 $eval_str = 'if(';
 for($i=0; $i < count($condArray); $i++){
    $eval_str .= evaluateConditions($condArray[$i], $varablesArray);
    if($i != count($condArray)-1){$eval_str .= ' || ';}  
 }   
 $eval_str .= '){return 1;}else{return 0;}';

 return eval($eval_str);

 }
 if (strtoupper($condArray['relation']) == 'AND'){
 unset($condArray['relation']);
 $eval_str = 'if(';
 for($i=0; $i < count($condArray); $i++){
    $eval_str .= evaluateConditions($condArray[$i], $varablesArray);
    if($i != count($condArray)-1){$eval_str .= ' && ';}  
 }   
 $eval_str .= '){return 1;}else{return 0;}';

 return eval($eval_str);

 }
throw new Exception('General Error Occurred');
} //end of function

/////

try {
echo evaluateConditions($conditions, $input_variables);
} 
catch (Exception $e) {
echo 'Caught exception: ',  $e->getMessage(), "\n";
}   
like image 400
BDS1400 Avatar asked Sep 04 '12 20:09

BDS1400


Video Answer


1 Answers

The easiest way to handle this would be recursion using PHP's eval() method (http://php.net/manual/en/function.eval.php):

static function evaluateArray($inArray)
{
  if (!$inArray['relation']) return eval($inArray['var'] + $inArray['compare'] + $inArray['value']);
  if ($inArray['relation'] == 'OR') return eval(evaluateArray($inArray[0])+'||'+evaluateArray($inArray[1]));
  if ($inArray['relation'] == 'AND') return eval(evaluateArray($inArray[0])+'&&'+evaluateArray($inArray[1]));
  return false; //could throw exception here if you wanted
}

This is designed to work with strings, but could be modified easily. Also, you should probably check to make sure that each subarray is properly structured, but I've left this code out.

like image 136
Sam Grondahl Avatar answered Oct 10 '22 16:10

Sam Grondahl