Make WordPress Core

Opened 4 years ago

Closed 3 years ago

Last modified 3 years ago

#53218 closed enhancement (fixed)

Make apply_filters() variadic

Reported by: johnbillion's profile johnbillion Owned by: johnbillion's profile johnbillion
Milestone: 6.0 Priority: normal
Severity: normal Version: 5.3
Component: Plugins Keywords: has-patch early commit needs-dev-note needs-docs
Focuses: Cc:

Description

Previously in #47678 most functions in core that call func_get_args() were converted to variadic functions. One exception is apply_filters() which was left as-is due to a concern about filters which pass (and expect) a value by reference:

WP_Hooks::apply_filters() can not be simplified further as - even within WP Core -, there are filter functions which expect to receive the $value to be filtered by reference.

Ref: https://core.trac.wordpress.org/ticket/47678#comment:31

It does seem however that this function can be made variadic by adding an additional parameter after $value instead of making $value variadic. The existing tests pass with this change, but the test coverage might not be sufficient.

There are two potential outcomes to this ticket:

  1. Make apply_filters() variadic by adding an additional ...$args parameter, leaving the existing $value parameter alone, or
  2. Add tests which demonstrate why this cannot be done

Change History (20)

This ticket was mentioned in PR #1259 on WordPress/wordpress-develop by johnbillion.


4 years ago
#1

  • Keywords has-patch added; needs-patch removed

#2 @johnbillion
3 years ago

Would like to get your input @jrf when you have time.

#3 @jrf
3 years ago

@johnbillion I've had a quick look and I would strongly recommend against this patch.

The performance of a function like array_merge() is often even worse than func_get_args(), so in effect, especially with using it twice, this would make one of the most used functions in WP slower, instead of faster, decreasing the overall performance (which the variadic changes were about).

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

#4 @jrf
3 years ago

Oh and just for reference:

WP_Hooks::apply_filters() can not be simplified further as - even within WP Core -, there are filter functions which expect to receive the $value to be filtered by reference.

This remark was about the WP_Hooks::apply_filters() class method, not about the global apply_filters() function (which the current patch is touching).

#5 @jrf
3 years ago

This is the comment which actually does apply to the global apply_filters() function and why it wasn't changed in the previous ticket:

For the remaining calls to func_get_args() I didn't see any real benefit in making this change for various reasons.

https://core.trac.wordpress.org/ticket/47678#comment:30

And for this particular case the reason was that a patch would result in what is currently proposed, which would not have a beneficial effect on performance.

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

#6 @jrf
3 years ago

P.S.: thanks for the ping 😉

#7 follow-up: @johnbillion
3 years ago

In PR 1259 I decided to revisit this with a view to removing as much of the args array processing in apply_filters() as possible in order to introduce the variadic $args parameter without negatively affecting performance.

As Juliette noted above, using array_merge() in place of func_get_args() and array_shift() results in a slight reduction in performance. What we can do instead is move the func_get_args() call inside the all hook handling block so it's not called when all isn't in use, switch to a variadic $args, and replace array_pop( $args ) with array_unshift() to push the $value variable onto the front of $args before it's passed to WP_Hook::apply_filters(). This results in no performance change down to the microsecond.

The all hook handling now uses the same handling as in do_action(). func_get_args() is more performant than array_unshift( $args, $hook_name ).

What's the overall gain of this change? A more correct signature for apply_filters() with no negative performance impact.

Benchmarking

The standard deviations of the benchmarks for this change are quite high because the processing time is so low. With 100,000 iterations the change averages to +/- less than 1/10th of a microsecond.

Benchmark results can be seen in the action here: https://github.com/WordPress/wordpress-develop/actions/runs/1243401754

Example:

old with callback 2.240μs
new with callback 2.230μs
old without callback 0.190μs
new without callback 0.182μs

#8 in reply to: ↑ 7 @SergeyBiryukov
3 years ago

Replying to johnbillion:

In PR 1259 I decided to revisit this with a view to removing as much of the args array processing in apply_filters() as possible in order to introduce the variadic $args parameter without negatively affecting performance.

Thanks for revisiting! The PR looks good to me at a glance.

#9 @johnbillion
3 years ago

  • Milestone changed from Future Release to 6.0

#10 @johnbillion
3 years ago

  • Keywords early added

#11 @johnbillion
3 years ago

  • Keywords dev-feedback added

I'd like to get this in. Any objections?

#12 @dingo_d
3 years ago

This would be a great addition, especially from the perspective of static analysis tools like PHPStan.

Currently, you get tons of false positives when passing more than two arguments, and you need to ignore the rule altogether, which diminishes the use of the tool.

#13 @davidbaumwald
3 years ago

  • Keywords commit added; dev-feedback removed

Took a look at the PR the PR and it looks good. Tested locally and ran unit tests. I feel like it's good to go. Spoke with @johnbillion, and he'll be committing this soon!

#14 follow-up: @peterwilsoncc
3 years ago

  • Owner set to johnbillion
  • Status changed from new to assigned

Assigning to @johnbillion for commit.

The PR includes .github/workflows/phpbench-tests.yml, are you intending to include that as part of the commit or is it simply for generating the reports during development?

#15 in reply to: ↑ 14 @johnbillion
3 years ago

Replying to peterwilsoncc:

The PR includes .github/workflows/phpbench-tests.yml, are you intending to include that as part of the commit or is it simply for generating the reports during development?

Just for development 👍

#16 follow-up: @johnbillion
3 years ago

  • Resolution set to fixed
  • Status changed from assigned to closed

In 52952:

Plugins: Convert apply_filters() into a proper variadic function.

This makes its signature more correct by implementing the spread operator, and adjusts the internal logic correspondingly without affecting performance.

Props jrf, SergeyBiryukov, davidbaumwald, mauriac, johnbillion

Fixes #53218

#18 in reply to: ↑ 16 @azouamauriac
3 years ago

Replying to johnbillion:

Props jrf, SergeyBiryukov, davidbaumwald, mauriac, johnbillion

Not sure we can fix this, but just let you know, my username is @azouamauriac not mauriac. thanks.

#19 @milana_cap
3 years ago

  • Keywords needs-dev-note needs-docs added

This one probably needs updating usage example in code https://core.trac.wordpress.org/browser/trunk/src/wp-includes/plugin.php?rev=52952#L135,L151

And most likely reviewing user contributed notes in
https://developer.wordpress.org/reference/functions/apply_filters/

#20 @johnbillion
3 years ago

I don't believe any of the docs need changing because the usage hasn't changed, just the internals. Anything I'm missing?

Note: See TracTickets for help on using tickets.