diff --git a/src/wp-includes/compat.php b/src/wp-includes/compat.php index f0bdf079742f1..84e611faee5e8 100644 --- a/src/wp-includes/compat.php +++ b/src/wp-includes/compat.php @@ -539,6 +539,48 @@ function array_all( array $array, callable $callback ): bool { // phpcs:ignore U } } +if ( ! function_exists( 'array_first' ) ) { + /** + * Polyfill for `array_first()` function added in PHP 8.5. + * + * Returns the first element of an array. + * + * @since 6.9.0 + * + * @param array $array The array to get the first element from. + * @return mixed|null The first element of the array, or null if the array is empty. + */ + function array_first( array $array ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.arrayFound + if ( empty( $array ) ) { + return null; + } + + foreach ( $array as $value ) { + return $value; + } + } +} + +if ( ! function_exists( 'array_last' ) ) { + /** + * Polyfill for `array_last()` function added in PHP 8.5. + * + * Returns the last element of an array. + * + * @since 6.9.0 + * + * @param array $array The array to get the last element from. + * @return mixed|null The last element of the array, or null if the array is empty. + */ + function array_last( array $array ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.arrayFound + if ( empty( $array ) ) { + return null; + } + + return $array[ array_key_last( $array ) ]; + } +} + // IMAGETYPE_AVIF constant is only defined in PHP 8.x or later. if ( ! defined( 'IMAGETYPE_AVIF' ) ) { define( 'IMAGETYPE_AVIF', 19 ); diff --git a/tests/phpunit/tests/compat/arrayFirst.php b/tests/phpunit/tests/compat/arrayFirst.php new file mode 100644 index 0000000000000..cd3708d06403b --- /dev/null +++ b/tests/phpunit/tests/compat/arrayFirst.php @@ -0,0 +1,95 @@ +assertTrue( function_exists( 'array_first' ) ); + } + + /** + * @ticket 63853 + * + * @dataProvider data_array_first + * + * @param mixed $expected The value extracted from the given array. + * @param array $arr The array to get the first value from. + */ + public function test_array_first( $expected, $arr ): void { + $this->assertSame( $expected, array_first( $arr ) ); + } + + + /** + * Data provider. + * + * @return array[] + */ + public function data_array_first(): array { + $obj = new \stdClass(); + return array( + 'string values' => array( + 'expected' => 'a', + 'arr' => array( 'a', 'b', 'c' ), + ), + 'associative array' => array( + 'expected' => 10, + 'arr' => array( + 'foo' => 10, + 'bar' => 20, + ), + ), + 'empty array' => array( + 'expected' => null, + 'arr' => array(), + ), + 'single element array' => array( + 'expected' => 42, + 'arr' => array( 42 ), + ), + 'null values' => array( + 'expected' => null, + 'arr' => array( null, 'b', 'c' ), + ), + 'objects' => array( + 'expected' => $obj, + 'arr' => array( + $obj, + 1, + 2, + ), + ), + 'boolean values' => array( + 'expected' => false, + 'arr' => array( false, true, 1, 2, 3 ), + ), + ); + } + + /** + * Test that array_first() returns the pointer is not the first element. + * + * @ticket 63853 + */ + public function test_array_first_with_end_pointer() { + $arr = array( + 'key1' => 'val1', + 'key2' => 'val2', + ); + // change the pointer to the last element + end( $arr ); + + $val = array_first( $arr ); + $this->assertSame( 'val2', current( $arr ) ); + $this->assertSame( 'val1', $val ); + } +} diff --git a/tests/phpunit/tests/compat/arrayLast.php b/tests/phpunit/tests/compat/arrayLast.php new file mode 100644 index 0000000000000..fc6ba394d2a02 --- /dev/null +++ b/tests/phpunit/tests/compat/arrayLast.php @@ -0,0 +1,84 @@ +assertTrue( function_exists( 'array_last' ) ); + } + + /** + * @ticket 63853 + * + * @dataProvider data_array_last + * + * @param mixed $expected The expected last value. + * @param array $arr The array to get the last value from. + */ + public function test_array_last( $expected, $arr ): void { + $this->assertSame( $expected, array_last( $arr ) ); + } + + /** + * Data provider for array_last(). + * + * @return array[] + */ + public function data_array_last(): array { + $obj = new \stdClass(); + return array( + 'string values' => array( + 'expected' => 'c', + 'arr' => array( 'a', 'b', 'c' ), + ), + 'associative array' => array( + 'expected' => 20, + 'arr' => array( + 'foo' => 10, + 'bar' => 20, + ), + ), + 'empty array' => array( + 'expected' => null, + 'arr' => array(), + ), + 'single element array' => array( + 'expected' => 42, + 'arr' => array( 42 ), + ), + 'null values' => array( + 'expected' => null, + 'arr' => array( 'a', 'b', null ), + ), + 'objects' => array( + 'expected' => $obj, + 'arr' => array( + 1, + 2, + $obj, + ), + ), + 'boolean values' => array( + 'expected' => false, + 'arr' => array( true, false ), + ), + 'null values in between' => array( + 'expected' => 'c', + 'arr' => array( 'a', null, 'b', 'c' ), + ), + 'empty string values' => array( + 'expected' => '', + 'arr' => array( 'a', 'b', '' ), + ), + ); + } +}