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 | 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
#2
@
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
@
3 years ago
introduced here: [46568]
#4
@
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.
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)