phparraysobject

Check if object with property = value exists in array of objects


I think I could do this with a foreach loop like this:

foreach ($haystack as $item){
   if (isset($item->$needle_field) && $item->$needle_field == $needle){
       return true;
   } 
} 

but I was wondering if it could be done without a loop?

something like:

if(in_array($item->$needle_field == $needle,$haystack){
    return true;
}

Solution

  • Latest Edit: As of PHP8.4, array_any() is a advantageous functional-style tool because it is designed (for performance) to short circuit upon encountering a true evaluation in the callback. This means that the function is protected from needlessly traversing the entire payload if qualifying data is found. This is effectively the foreach() approach below, but with the elegance of a function call. Demo

    $needleField = 'cats';
    $needleValue = 2;
    
    var_export(
        array_any(
            $objects,
            fn($obj) => property_exists($obj, $needleField)
                && $obj->$needleField === $needleValue
        )
    );
    

    Yes, in modern PHP you can determine if a specific object property contains a specific value without a classic loop by combining the forces of array_column() (which has evolved to also handle arrays of objects) and in_array().

    Code: (Demo)

    $objects = [
        (object)['cats' => 2],
        (object)['dogs' => 2],
        (object)['fish' => 10],
        (object)['birds' => 1],
    ];
    
    $needleField = 'cats';
    $needleValue = 2;
    
    var_export(
        in_array($needleValue, array_column($objects, $needleField))
    );
    // output: true
    

    The advantage of this technique is the obviously concise syntax. This is a perfectly acceptable approach for relatively small volumes of data.

    A possible disadvantage to this technique is that array_column() will be generating a new array of all of values that relate to the $needleField.

    In my above demo, array_column() will only generate a single-element array because there is only one cats property in all of the objects. If we were processing a relatively large volume of data, then it would be inefficient to bother collecting all of the qualifying cats values and then run in_array() when only one match is necessary to return true.

    For "large" volumes of data where performance is a primary criterion for script design, a classic foreach loop would be a better choice and as soon as an object satisfies the rules, then the loop should be halted via return or break.

    Code: (Demo)

    function hasPropertyValue(array $objects, $property, $value): bool {
        foreach ($objects as $object) {
            if (property_exists($object, $property) && $object->{$property} === $value) {
                return true;
            }
        }
        return false;
    }
    var_export(
        hasPropertyValue($objects, $needleField, $needleValue)
    );