Make WordPress Core

Opened 6 weeks ago

Closed 4 weeks ago

Last modified 3 days ago

#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() in src/wp-includes/admin-bar.php
  • _wp_personal_data_handle_actions() in src/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)

#1 @mukesh27
6 weeks ago

  • Owner set to mukesh27
  • Status newassigned

This ticket was mentioned in PR #12785 on WordPress/wordpress-develop by @mukesh27.


6 weeks ago
#2

  • Keywords has-patch added; needs-patch removed

Trac ticket: https://core.trac.wordpress.org/ticket/65773

Replace current( array_keys( $array ) ) with array_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 $actions array grows with the number of registered post types.

## Use of AI Tools

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() returns false while array_key_first() returns null. None of the touched call sites compares the result with ===, and most sit behind an empty() 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() returns null quietly.

#4 @westonruter
5 weeks ago

  • Milestone Future Release7.2
  • Owner changed from mukesh27 to westonruter
  • Status assignedreviewing

#5 @westonruter
4 weeks ago

  • Resolutionfixed
  • Status reviewingclosed

In 63297:

Code Modernization: Use array_key_first() for an array's first key.

current( array_keys( $array ) ) builds a complete array of every key only to read the first one and discard the rest, whereas array_key_first() reads the first bucket directly. The function has been native since PHP 7.3, below the current minimum supported version, and core already uses it in wp_replace_in_html_tags(). Behavior is unchanged: the toolbar's $actions cannot be empty at that point, and in the privacy tools absint() normalizes null and false alike.

Developed in https://github.com/WordPress/wordpress-develop/pull/12785.
Follow-up to r18788, r42986.

Props mukesh27, soean.
Fixes #65773.

#6 @SergeyBiryukov
3 days ago

In 63567:

Code Modernization: Use array_key_first() to read the first key of an array.

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 r63297 / #65773, which is scoped to the two nested current( array_keys( $array ) ) call sites. This commit 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.

Behavior notes

  • On an empty array reset() returns false while array_key_first() returns null. None of the touched call sites compares the result with ===, and most sit behind an empty() 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() returns null quietly.

Developed in https://github.com/WordPress/wordpress-develop/pull/12790.

Follow-up to r63297.

Props Soean, mukesh27.
See #65773.

@SergeyBiryukov commented on PR #12790:


3 days ago
#7

Thanks for the PR! Merged in r63567.

Note: See TracTickets for help on using tickets.