Make WordPress Core

Opened 22 months ago

Last modified 3 months ago

#55105 reopened feature request

Introduce a polyfill for `array_is_list()`.

Reported by: costdev's profile costdev Owned by:
Milestone: 6.5 Priority: normal
Severity: minor Version:
Component: General Keywords: has-patch has-unit-tests
Focuses: Cc:

Description

PHP 8.1 introduces a new function, array_is_list().

The function determines whether an array's keys consist of consecutive numbers from 0 to count( $arr ) - 1.

Including a polyfill will allow developers to take advantage of the new function.

Notes

  • A list must start from an offset of 0. array( 2 => 'one', 3 => 'two' ); will return false.
  • An empty array will return true.

References

Attachments (1)

55105.diff (3.8 KB) - added by costdev 20 months ago.

Download all attachments as: .zip

Change History (16)

#1 @SergeyBiryukov
22 months ago

  • Milestone changed from Awaiting Review to 6.0

This ticket was mentioned in PR #2289 on WordPress/wordpress-develop by costdev.


22 months ago
#2

  • Keywords has-patch has-unit-tests added

#3 @costdev
22 months ago

PR ready for review.

#4 @rafiahmedd
22 months ago

@costdev sorry if I am wrong, I think on line 500 it will be if( $k !== $i ) then return false.

#5 follow-up: @costdev
22 months ago

Hi @rafiahmedd, thanks for reviewing the PR! I left a comment there about pre-incrementation vs post-incrementation.

#6 in reply to: ↑ 5 @rafiahmedd
22 months ago

Replying to costdev:

Hi @rafiahmedd, thanks for reviewing the PR! I left a comment there about pre-incrementation vs post-incrementation.

@costdev thank you brother 😊

#7 @jrf
22 months ago

I'm wondering why this function should be polyfilled. Can you give one or more examples of code in WordPress which would benefit from the function being available ?

If there are no current usecases for this function in Core, the function shouldn't be introduced.

#8 @davidbaumwald
21 months ago

  • Keywords dev-feedback added

#9 @costdev
21 months ago

@jrf I tried to find a use case prior to writing the polyfill. I couldn't find one. Examples online seem to literally just reiterate what the function does, without providing use cases, and vaguely referring to "PHP security vulnerabilities caused by arrays that are not in order", without mentioning array_values() once.

Why did I write it then?

I'd just reviewed and written tests for some of the polyfills introduced in 5.9, and I wasn't quite done with my polyfilling-spree. It's there, with unit tests, if use cases are found.

As we're still early enough in the release cycle, I'll leave this open in case someone sees value in introducing this polyfill to Core. If there are none provided as we approach feature freeze, I'll go ahead and close as maybelater, or punt to 6.1 if use cases are actively being discussed.

#10 @peterwilsoncc
20 months ago

  • Version 5.9 deleted

Feature requests don't require a version, so I have removed that.

@costdev As there hasn't been any additional discussion, are you able to decide whether you'd like to have another go in a future milestone or close this as maybelater?

#11 follow-up: @costdev
20 months ago

  • Keywords dev-feedback removed
  • Milestone 6.0 deleted
  • Resolution set to maybelater
  • Status changed from new to closed

Yeah, let's close this one as maybelater so it can be picked up, with unit tests, if use cases are found.

For some futureproofing, I'll close the PR and upload a .diff to the ticket, which will include an additional dataset for array( NAN ).

Some history for contributors who may look at this in future:

  1. The patch uses foreach ( $arr... instead of array_keys( $arr ) or array_keys($arr) === range(count($arr)-1) to avoid creating new arrays unnecessarily. This means only one pass over the array, and is in line with the example given in the RFC's Proposal section.
  2. An early return for an empty array is not included because an empty array will skip on the foreach() and return true.
  3. An alternative implementation used by Symfony has an early return on $array === array_values($array). The performance improvement from this early return is negligible, but importantly, performance is inconsistent across different versions of PHP, so I think the current implementation is the simplest and most effective polyfill for array_is_list().

@costdev
20 months ago

costdev commented on PR #2289:


20 months ago
#12

Closed in favour of 55105.diff.

#13 @johnjamesjacoby
14 months ago

Some random related thoughts...


See also: wp_is_numeric_array() & rest_is_array() for similar but different examples of functions in WordPress that are documented to imply their intention may have been to mimic the behavior of array_is_list() but perhaps a consult from @rmccue would be helpful?

The above helper function(s) @return bool Whether the variable is a list but do not enforce @costdev's first point:

A list must start from an offset of 0

(emphasis, mine... but I think I agree?)

While a bunch of other programming languages explicitly define & strictly enforce "List" and "Array" as different things (C, Java, Python, etc...) neither PHP nor WordPress do currently.

I think that means it is safe to suggest that WordPress functions named like wp_parse_list() and wp_list_*() – and the WP_List_Util() class – largely imply that they are intended to work with either arrays or objects. Similarly, only the REST API (and later the Meta API via default values in get_metadata_default()) have experienced a need for identifying whether a variable value was a numerically indexed array that starts with 0 and does not omit any subsequent integers as keys until the final key.


Without speculating too deeply, PHP core is trending towards becoming more strict (hence more static), so perhaps someday a "List" could be a more explicitly defined thing, and it may behoove WordPress core contributors to have a plan for that and decide whether to:

  • Keep down the path of generalized "lists" as arrays or objects
  • Add to the global namespace list functions & classes that mean what array_is_list() means

#14 @swissspidy
3 months ago

The Performant Translations feature plugin is one project that uses array_is_list() (ref) and would require this polyfill upon core merge.

#15 in reply to: ↑ 11 @SergeyBiryukov
3 months ago

  • Milestone set to 6.5
  • Resolution maybelater deleted
  • Status changed from closed to reopened

Replying to costdev:

Yeah, let's close this one as maybelater so it can be picked up, with unit tests, if use cases are found.

It is worth noting that polyfills for array_key_first() and array_key_last() were added in [52038] / #45055 even without being used by WordPress core.

I believe the benefit here is pretty much the same as in that ticket:

Including a polyfill would allow developers to take advantage of the new functions and write consistent code regardless of a site's PHP version.

Now that WordPress has PHP 8.1 compatibility (with exceptions), I think it's time to reconsider this.

With 6.4 Beta 1 coming in a few days, moving to 6.5 for discussion.

Note: See TracTickets for help on using tickets.