<?php
$obj = new stdClass();
$obj->a = 5;
$obj->b = 2;
$obj->c = 9;
$filter = array(
'logic' => 'AND',
'filters' => array(
array('field' => 'a', 'operator' => '===', 'value' => 5),
array(
'logic' => 'OR',
'filters' => array(
array('field' => 'b', 'operator' => '===', 'value' => 6),
array('field' => 'c', 'operator' => '<', 'value' => 10),
),
),
),
);
function process(string $logic, array $filters, object $obj): bool
{
// For an AND, all things must be true, so if we're given 5 things, all 5 must be true.
// For an OR, only one needs to be true.
$targetCount = 'AND' === $logic ? count($filters) : 1;
// How many items were true
$currentCount = 0;
foreach ($filters as $filter) {
// The sub-array is a grouping, grab parts, process, and if true, increment our local counter
if (array_key_exists('logic', $filter)) {
if (process($filter['logic'], $filter['filters'], $obj)) {
$currentCount++;
}
// For a sub-array, don't process anything else
continue;
}
// Grab array items as variables just for ease of use
$field = $filter['field'];
$operator = $filter['operator'];
$value = $filter['value'];
// Match on the operator. For lower versions of PHP a switch(true) or just an if could be used, too.
$result = match ($operator) {
'===' => $obj->$field === $value,
'==' => $obj->$field == $value,
'>=' => $obj->$field >= $value,
'>' => $obj->$field > $value,
'<=' => $obj->$field <= $value,
'<' => $obj->$field < $value,
};
// If success, increment our counter
if ($result) {
$currentCount++;
// If we've reach our target, return success
// This could also just be "if process = OR"
if ($currentCount === $targetCount) {
return true;
}
}
}
// See if we met the final condition outside of the loop
return $currentCount === $targetCount;
}
echo process($filter['logic'], $filter['filters'], $obj) ? 'yes' : 'no';
Here you find the average performance (time & memory) of each version. A grayed out version indicates it didn't complete successfully (based on exit-code).