Make WordPress Core

Opened 3 years ago

Last modified 2 years ago

#55133 new defect (bug)

Using an array containing a single object as first $arg in do_action()

Reported by: pskli's profile pskli Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version:
Component: Plugins Keywords: has-patch 2nd-opinion needs-dev-note
Focuses: Cc:

Description

When passing an array containing 1 single object as the first argument of do_action(), the array is automatically flattened and all functions triggered by the hook will receive a single object as the first argument (instead of an array).

Example:

$var = [
        (object) [
                'key'   => 'name',
                'value' => 'Pierre',
        ]
]; 

do_action( 'hook_name', $var );

Any function hooked to hook_name receives this first argument:

stdClass Object
(
    [key] => name
    [value] => Pierre
)

…instead of an array containing this object.

I've found that this is because of some PHP4 backward compatibility in the do_action() function:

} elseif ( is_array( $arg[0] ) && 1 === count( $arg[0] ) && isset( $arg[0][0] ) && is_object( $arg[0][0] ) ) {
        // Backward compatibility for PHP4-style passing of `array( &$this )` as action `$arg`.
        $arg[0] = $arg[0][0];
}

This is a weird and unexpected behavior, could we add an additional condition in this elseif in order to check for the PHP version to apply this hack?

Change History (7)

This ticket was mentioned in PR #2300 on WordPress/wordpress-develop by psaikali.


3 years ago
#1

  • Keywords has-patch added

https://core.trac.wordpress.org/ticket/55133

Removing the PHP4 backward-compatibility in the do_action() function to avoid unexpected behaviour where the first argument is an array of a single object, as it's currently flattened and become a variable containing the single object.

Trac ticket: [](https://core.trac.wordpress.org/ticket/55133)

#2 @audrasjb
3 years ago

  • Keywords 2nd-opinion needs-dev-note added
  • Version 5.9 deleted

Hello @pskli and thanks for raising this,

We don't need PHP4 backwards compatibility anymore so removing this fallback makes sense, however I'm feeling a bit hesitant since changing this could break plugins relying on the current behavior.

This change would at least need a dev note, and probably further investigation to make sure this is not a massive breaking change in the ecosystem.

#3 in reply to: ↑ description @azouamauriac
3 years ago

introduced here: [46568]

#4 @pskli
3 years ago

Honestly, I'm wondering how this kind of behavior mentioned in this ticket has not been mentioned previously by plugin devs, as:

function do_action_with_array_of_unique_object() {
        $var = [ get_post( 1 ) ];
        do_action( 'some_action', $var );
}

function debug_unique_post_variable( $array_with_one_wp_post ) {
        error_log( print_r( $array_with_one_wp_post, true ) );
}
add_action( 'some_action', __NAMESPACE__ . '\\debug_unique_post_variable', 10, 1 );

…would result in getting a WP_Post instead of an array.

I agree that it could break plugins relying on the current behavior, but I believe that they're probably doing an ! is_array( $var ) { $var = [ $var ]; } to bypass this unexpected result, don't you think?

The current result, in this (rare?) specific case (where $arg should be an array containing 1 object) is unexpectedly weird.

Last edited 3 years ago by pskli (previous) (diff)

#5 @dlh
3 years ago

Duplicate of #40284?

#6 @SergeyBiryukov
2 years ago

#55998 was marked as a duplicate.

#7 @SergeyBiryukov
2 years ago

#40284 was marked as a duplicate.

Note: See TracTickets for help on using tickets.