#65773 closed enhancement (fixed)
Use array_key_first() instead of current( array_keys() ) to read an array's first key
| Reported by: | mukesh27 | Owned by: | westonruter |
|---|---|---|---|
| Priority: | normal | Milestone: | 7.2 |
| Component: | General | Version: | |
| Severity: | normal | Keywords: | has-patch |
| Cc: | Focuses: | performance |
Description
Two places in core read the first key of an array via current( array_keys( $array ) ):
wp_admin_bar_new_content_menu()insrc/wp-includes/admin-bar.php_wp_personal_data_handle_actions()insrc/wp-admin/includes/privacy-tools.php
array_keys() builds a complete array of every key only to read the first one and discard the rest. array_key_first() reads the first bucket directly in constant time and allocates nothing.
The toolbar case runs on every admin page load, and on every front-end load for logged-in users with the toolbar visible. Its $actions array grows with the number of registered post types, so the saving scales with the site.
No behaviour change: in both cases the array is non-empty at the point of the call, and the empty-array return values (false vs null) are both normalised by the surrounding absint() / admin_url() calls.
Change History (7)
This ticket was mentioned in PR #12785 on WordPress/wordpress-develop by @mukesh27.
6 weeks ago
#2
- Keywords has-patch added; needs-patch removed
This ticket was mentioned in PR #12790 on WordPress/wordpress-develop by @Soean.
6 weeks ago
#3
Reading the first key of an array through array_keys() allocates a full array of every key just to keep one entry and discard the rest. array_key_first() reads the first bucket directly.
Follow-up to 65773, which is scoped to the two nested current( array_keys( $array ) ) call sites and is addressed in #12785. This PR covers a second shape of the same idea, which that ticket does not include: the key array is assigned to a variable first, then read on the next line.
$keys = array_keys( $wp_registered_sidebars ); $sidebar = reset( $keys );
$sidebar = array_key_first( $wp_registered_sidebars );
13 occurrences across 11 files, in two shapes — reset( $keys ) and $keys[0]. In every case the intermediate variable existed only to carry the key array to the next line and is never read again afterwards.
### One change that goes further
In spawn_cron() and _wp_cron() the surrounding check is dropped too:
$keys = array_keys( $crons ); if ( isset( $keys[0] ) && $keys[0] > $gmt_time ) {
if ( array_key_first( $crons ) > $gmt_time ) {
Both functions return early a few lines above when $crons is empty, so isset( $keys[0] ) can never be false there. Happy to keep an explicit null !== $first guard instead if reviewers prefer the defensive form.
### Behavior notes
- On an empty array
reset()returnsfalsewhilearray_key_first()returnsnull. None of the touched call sites compares the result with===, and most sit behind anempty()guard. - Where the old code used
$keys[0], the new code is strictly safer:$keys[0]emitted a notice on an empty array,array_key_first()returnsnullquietly.
@SergeyBiryukov commented on PR #12790:
3 days ago
#7
Thanks for the PR! Merged in r63567.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)
Trac ticket: https://core.trac.wordpress.org/ticket/65773
Replace
current( array_keys( $array ) )witharray_key_first( $array ). The former builds a complete array of every key only to read the first one and throw the rest away, which costs O(n) time and O(n) memory;array_key_first()reads the first bucket directly in constant time and allocates nothing.wp_admin_bar_new_content_menu()runs on every admin page load and on every front-end load for logged-in users with the toolbar visible, and its$actionsarray grows with the number of registered post types.## Use of AI Tools