Here's a basic solution
function array_find($xs, $f) {
foreach ($xs as $x) {
if (call_user_func($f, $x) === true)
return $x;
}
return null;
}
array_find([1,2,3,4,5,6], function($x) { return $x > 4; }); // 5
array_find([1,2,3,4,5,6], function($x) { return $x > 10; }); // null
In the event $f($x) returns true, the loop short circuits and $x is immediately returned. Compared to array_filter, this is better for our use case because array_find does not have to continue iterating after the first positive match has been found.
In the event the callback never returns true, a value of null is returned.
Note, I used call_user_func($f, $x) instead of just calling $f($x). This is appropriate here because it allows you to use any compatible callable
Class Foo {
static private $data = 'z';
static public function match($x) {
return $x === self::$data;
}
}
array_find(['x', 'y', 'z', 1, 2, 3], ['Foo', 'match']); // 'z'
Of course it works for more complex data structures too
$data = [
(object) ['id' => 1, 'value' => 'x'],
(object) ['id' => 2, 'value' => 'y'],
(object) ['id' => 3, 'value' => 'z']
];
array_find($data, function($x) { return $x->id === 3; });
// stdClass Object (
// [id] => 3
// [value] => z
// )
If you're using PHP 7, add some type hints
function array_find(array $xs, callable $f) { ...
If your array may contain null elements, array_find cannot return null to signal no element was not found. As @dossy suggests, you could use an array result containing either one or zero elements -
function array_find($xs, $f) {
foreach ($xs as $x) {
if (call_user_func($f, $x) === true)
return [$x]; // result
}
return []; // not found
}
array_find([1,2,3,4,5,6], function($x) { return $x > 4; }); // [5]
array_find([1,2,3,4,5,6], function($x) { return $x > 10; }); // []
foreachin a log of locations yield more concise an more readable code.