php: write php 8.4’s array_find from scratch

there’s an rfc vote currently underway for a number of new array functions in php8.4 (thanks to symfony station for pointing this out!). the proposal is for four new functions for finding and evaluating arrays using callables. the functions are:

  • array_find()
  • array_find_key()
  • array_any()
  • array_all()

the full details can be read here.

if we’re impatient, though, we can skip waiting for php8.4 and homeroll these ourselves.

array_find()

at it’s heart, the functionality of array_find is array_filter. the major difference is that array_find returns only the first element of the array, not all of them.

with that in mind, we can build our own version like so:

/** * Find the first value in an array that evaluates to true in $func * * @param array $array * @param callable $func * @return any */
$array_find = function(array $array, callable $func) { return array_values(array_filter($array, $func))[0] ?? null;
};
Enter fullscreen mode
Exit fullscreen mode

when we run this against the test data given in the rfc, we get the expected results.

$array = [ 'a' => 'dog', 'b' => 'cat', 'c' => 'cow', 'd' => 'duck', 'e' => 'goose', 'f' => 'elephant'
];
$array_find($array, function (string $value) { return strlen($value) > 4;
}); // string(5) "goose"
Enter fullscreen mode
Exit fullscreen mode

array_find_key()

the only difference between array_find_key and array_find is that the one that is called ‘find_key’ finds the key, not the value. no surprise.

we can implement this by taking our array_find code and adding array_key_first:

/** * Find the first key in an array where the value evaluates to true in $func * * @param array $array * @param callable $func * @return any */
$array_find_key = function(array $array, callable $func) { return array_key_first(array_filter($array, $func)) ?? null;
};
Enter fullscreen mode
Exit fullscreen mode

array_any() and array_all()

both array_any and array_all return booleans.

if one or more of the elements in the array passes the test in the callable, array_any will return true. we can achieve this by filtering the array and testing if the count of the result is greater than zero:

/** * Evaluate if any element in array $array evaluates to true in $func * * @param array $array * @param callable $func * @return bool */
$array_any = function(array $array, callable $func): bool { return (bool)count(array_filter($array, $func));
};
Enter fullscreen mode
Exit fullscreen mode

for array_all, all the elements in the array must pass the callable test. this requires us to test if the number of elements in the filtered array is the same as in the original array before filtering, ie. if all the elements passed the filter.

/** * Evaluate if all elements in array $array evaluates to true in $func * * @param array $array * @param callable $func * @return bool */
$array_all = function(array $array, callable $func): bool { return count(array_filter($array, $func)) == count($array);
};
Enter fullscreen mode
Exit fullscreen mode

and now we have a small slice of the power of php8.4 without the wait.

🔎 this post was originally written in the grant horwood technical blog


Discover more from Coursity

Subscribe to get the latest posts sent to your email.

Leave a Comment

Your email address will not be published. Required fields are marked *

Discover more from Coursity

Subscribe now to keep reading and get access to the full archive.

Continue reading

Scroll to Top