diff --git a/src/functions.php b/src/functions.php index 57f2d9b..e7f9be0 100644 --- a/src/functions.php +++ b/src/functions.php @@ -72,6 +72,22 @@ function iterable_key_first($iterable) return null; } +/** + * Get the first value of an iterable + * + * @param iterable $iterable + * + * @return ?mixed + */ +function iterable_value_first($iterable) +{ + foreach ($iterable as $_ => $value) { + return $value; + } + + return null; +} + /** * Yield sets of items from a sorted traversable grouped by a specific criterion gathered from a callback * diff --git a/tests/FunctionsTest.php b/tests/FunctionsTest.php index 1263a11..e107e66 100644 --- a/tests/FunctionsTest.php +++ b/tests/FunctionsTest.php @@ -246,4 +246,41 @@ public function testYieldGroupsWithCallbackReturningCriterionValueAndKey() ) ); } + + public function testIterableValueFirstReturnsFirstValueIfIterableImplementsIteratorAndIsNotEmpty() + { + $this->assertSame('a', Stdlib\iterable_value_first(new ArrayIterator(['a', 'b']))); + } + + public function testIterableValueFirstReturnsFirstValueIfIterableIsArrayAndIsNotEmpty() + { + $this->assertSame('a', Stdlib\iterable_value_first(['a', 'b'])); + } + + public function testIterableValueFirstReturnsFirstValueIfIterableIsGeneratorAndIsNotEmpty() + { + $this->assertSame('a', Stdlib\iterable_value_first(call_user_func(function () { + yield 'a'; + yield 'b'; + }))); + } + + public function testIterableValueFirstReturnsNullIfIterableImplementsIteratorAndIsEmpty() + { + $this->assertNull(Stdlib\iterable_value_first(new ArrayIterator([]))); + } + + public function testIterableValueFirstReturnsNullIfIterableIsArrayAndIsEmpty() + { + $this->assertNull(Stdlib\iterable_value_first([])); + } + + public function testIterableValueFirstReturnsNullIfIterableIsGeneratorAndIsEmpty() + { + $this->assertNull(Stdlib\iterable_value_first(call_user_func(function () { + return; + /** @noinspection PhpUnreachableStatementInspection Empty generator */ + yield; + }))); + } }