Skip to content

Toolbar, Privacy: Use array_key_first() to read the first key of an array - #68

Draft
mukeshpanchal27 wants to merge 2 commits into
trunkfrom
perf/array-key-first
Draft

Toolbar, Privacy: Use array_key_first() to read the first key of an array#68
mukeshpanchal27 wants to merge 2 commits into
trunkfrom
perf/array-key-first

Conversation

@mukeshpanchal27

Copy link
Copy Markdown
Owner

Summary

Replaces current( array_keys( $array ) ) with array_key_first( $array ) in the two places core uses that idiom.

current( array_keys( $a ) ) reads a single key, but gets there by materialising a brand-new array containing every key in $a, reading element 0 of that throwaway array, then discarding it. That is O(n) time plus O(n) memory to answer a question PHP can answer in O(1) — array_key_first() reads the first bucket of the hash table directly and allocates nothing.

array_key_first() is available in PHP 7.3 and later, below the current minimum supported version, so no polyfill is involved.

Benchmark

200,000 iterations per row, PHP 8.x:

Array size current( array_keys( $a ) ) array_key_first( $a ) Speedup
5 keys 13.45 ms 7.15 ms 1.9x
20 keys 19.20 ms 7.12 ms 2.7x
100 keys 50.72 ms 7.10 ms 7.1x

The shape matters more than the absolute numbers: array_key_first() is flat regardless of array size, while current( array_keys() ) grows linearly with data that is never used.

Sites changed

File Line Note
src/wp-includes/admin-bar.php 1083 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. $actions holds one entry per registered post type the user can create, so sites with many CPTs pay proportionally more.
src/wp-admin/includes/privacy-tools.php 77 _wp_personal_data_handle_actions() — the retry branch of the privacy request list table.

Behaviour

The two idioms differ in exactly one respect: on an empty array, current( array_keys( $a ) ) returns false while array_key_first( $a ) returns null. Both sites are safe:

  • admin-bar.php — the function returns early ten lines above the change (if ( ! $actions ) { return; }), so $actions is guaranteed non-empty. The empty case is unreachable.
  • privacy-tools.php — the value goes straight into absint(), and absint( false ) and absint( null ) both evaluate to 0. Identical result.

For every non-empty array both expressions return the same key with the same type. There is also no array-pointer side effect to preserve: current() was being applied to the temporary array returned by array_keys(), never to $actions itself.

Testing instructions

php -l src/wp-includes/admin-bar.php
php -l src/wp-admin/includes/privacy-tools.php
vendor/bin/phpcs src/wp-includes/admin-bar.php src/wp-admin/includes/privacy-tools.php
npm run test:php -- --filter '(adminBar|privacy)'

Results on this branch:

  • php -l — no syntax errors in either file.
  • phpcs — clean, 0 errors / 0 warnings.
  • PHPUnit — OK (78 tests, 116 assertions).

Manually: load any admin screen as a user who can create posts and confirm the toolbar "New" node links to the same target as before.


This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See Contributing to WordPress for more information.

mukeshpanchal27 and others added 2 commits July 30, 2026 20:39
…rray.

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.

`array_key_first()` is available in PHP 7.3 and later, which is below the current
minimum supported version.

Props mukesh.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant