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.
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.
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.
$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
)
)
)
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";
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With