Make WordPress Core

Opened 18 months ago

Last modified 4 weeks ago

#60190 new enhancement

Drop PHP 4 support for arrays with 1 object element

Reported by: kkmuffme's profile kkmuffme Owned by:
Milestone: 6.9 Priority: normal
Severity: normal Version:
Component: Plugins Keywords: has-patch has-unit-tests early 2nd-opinion close
Focuses: Cc:

Description (last modified by sabernhardt)

do_action( 'foo', array( (object) null ) );

function foo_cb( array $arg ) {}
add_action( 'foo', 'foo_cb' );

This will fail with a fatal error in PHP 7+, since do_action (as the only one, this isn't an issue with apply_filters or do_action_ref_array) will convert arrays with only 1 object into that object.
The reason for that is some PHP 4 legacy behavior, see #48312

It's time to drop this PHP 4 support, as this prevent using native types in callback functions in cases where the argument is an array of objects.

Change History (15)

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


18 months ago
#1

  • Keywords has-patch has-unit-tests added

Drop PHP 4 support for do_action with 1 array<object> argument where the array contains only 1 element, in favor of better support for PHP 7+ native types

#2 @sabernhardt
18 months ago

  • Description modified (diff)

This ticket was mentioned in Slack in #core by kkmuffme. View the logs.


17 months ago

#4 @swissspidy
17 months ago

This will fail with a fatal error in PHP 7+

Can you elaborate on that? The existing test_action_args_with_php4_syntax test seems to work just fine without triggering errors.

#5 @kkmuffme
17 months ago

As outlined in OP it will lead to a fatal if any callback uses PHP native types for array; you'll get:

Fatal error: Uncaught TypeError: ... must be of type array, stdClass given

Now you could say: just use a union type array|object, but that is:
a) only available since PHP 8+
b) unnecessarily weakening the PHP type system to keep PHP 4 compat that has been deprecated since a decade at this point.

#6 @swissspidy
16 months ago

  • Keywords needs-unit-tests added; has-unit-tests removed
  • Milestone changed from Awaiting Review to Future Release
  • Type changed from defect (bug) to enhancement
  • Version trunk deleted

As outlined in OP it will lead to a fatal if any callback uses PHP native types for array; you'll get:

A test to demonstrate this would be great, just for completeness sake

Right now this patch removes a unit test, but the test actually still passes with the proposed patch, so why remove it?

@kkmuffme commented on PR #5839:


15 months ago
#7

Yes, I added a test now (which would result in a fatal error without this PR on standard WP 6.5)

#8 @kkmuffme
15 months ago

  • Keywords has-unit-tests added; needs-unit-tests removed

Right now this patch removes a unit test, but the test actually still passes with the proposed patch, so why remove it?

Tested it, not true. The test fails. Removed it again.

A test to demonstrate this would be great, just for completeness sake

Done. This test would result in a fatal error without the changes of this PR (tested on WP 6.5)
(had some confusion initially, since I wasn't familiar how the args are tested/returned in WP phpunit tests)

This ticket was mentioned in Slack in #core by kkmuffme. View the logs.


15 months ago

This ticket was mentioned in Slack in #core by kkmuffme. View the logs.


14 months ago

This ticket was mentioned in Slack in #core by mikachan. View the logs.


13 months ago

#12 @johnbillion
4 weeks ago

  • Milestone changed from Future Release to 6.9

#13 @johnbillion
4 weeks ago

  • Keywords early added

#14 @johnbillion
4 weeks ago

  • Keywords 2nd-opinion added

To clarify about the fatal error: this isn't actually related to native type handling, that's just where the fatal error occurs when a callback function receives an object as its first parameter instead of the expected array containing an object. The underlying problem is, as @kkmuffme mentions, that do_action will convert arrays with only 1 object into that object before passing it to the callbacks. Regardless of whether a callback uses a type declaration, it'll receive a value of the wrong type as its first parameter.

While I'm in favour of the fix and the tests in https://github.com/WordPress/wordpress-develop/pull/5839 I'm concerned about what might break. This is essentially a revert of [46568]. #48312 provides an example of code that will behave differently after this fix:

do_action( 'some_action', array( $this ) );

Currently a callback hooked into this action receives the object as its first parameter instead of an array containing the object. This proposed change "fixes" that but will break any existing code that works around this funky behaviour.

Does the fix justify the back-compat break?

CC @david.binda @SergeyBiryukov @azaozz

#15 @azaozz
4 weeks ago

  • Keywords close added

It's time to drop this PHP 4 support, as this prevent using native types in callback functions in cases where the argument is an array of objects.

This seems good however I tend to agree with @johnbillion that it shouldn't be breaking back-compat for existing code. The assumption is that there may be quite a few places that have adapted to using the existing code. Imho it seems better to perhaps document this well and leave it as-is.

The same seems to be valid for the desire to use native types in callback args. Generally it is a good idea, but unfortunately don't see how it can be implemented without breaking back-compat. (Well, there may be ways but seemingly not elegant at all.)

Note: See TracTickets for help on using tickets.