﻿id	summary	reporter	owner	description	type	status	priority	milestone	component	version	severity	resolution	keywords	cc	focuses	prnumber
47678	Modernize/simplify current_user_can()	jrf	pento	"As support for PHP < 5.6.20 has been dropped, certain modernizations can now be applied to WP.

The [https://developer.wordpress.org/reference/functions/current_user_can/ `current_user_can()`] function is used pretty often during a regular WP page-load and is a good candidate for modernization.

The patch I'm attaching contains this modernization.

To understand what I'm doing here, let's step through it.

**Step 1: simplify the function.**

The function contains the following redundant code:
{{{#!php
<?php
	$args = array_slice( func_get_args(), 1 );
	$args = array_merge( array( $capability ), $args );
}}}

What is happening here is that:
1. All arguments passed to the function are retrieved.
2. The first argument - the named parameter `$capability` - is sliced off, so `$args` is now only the arguments after `$capability`.
3. The arguments are merged back together in the same order as they were originally.

I've not done the code archeology to see how this code ever made into the code base as I'm not here to name and shame, but let's get rid of it.

Replacing this part of the code with the below has the exact same effect and removes two (badly performing) function calls:
{{{#!php
<?php
	$args = func_get_args();
}}}

To prove the point, see: https://3v4l.org/BqYY0


**Step 2: modernize the function declaration.**

The function currently declares one named, required parameter `$capability` and via the above mentioned `func_get_args()` allows for additional arguments to be passed.
This is also documented as such in the function documentation.
{{{#!php
<?php
/**
 * ...
 * @param string $capability Capability name.
 * @param mixed  ...$args    Optional further parameters, typically starting with an object ID.
 * @return bool Whether the current user has the given capability. If `$capability` is a meta cap and `$object_id` is
 *              passed, whether the current user has the given meta capability for the given object.
 */
function current_user_can( $capability ) {
}}}

PHP 5.6 introduced [https://www.php.net/manual/en/migration56.new-features.php#migration56.new-features.variadics variadic functions using the spread operator].

Now, we could make `$capability` variadic and remove the call to `func_get_args()`, but that would make the `$capability` parameter optional.
{{{#!php
<?php
function current_user_can( ...$capability ) {
}}}

Making the `$capability` parameter optional is not the intention as it:
* Changes the function signature.
* Could break the subsequent function call to `WP_User::has_cap()` to which `$capability` is passed, where `$capability` is not optional.

So, instead, we add a new variadic (and therefore by nature optional) parameter `$args`.
{{{#!php
<?php
function current_user_can( $capability, ...$args ) {
}}}

This is completely in line with the existing function documentation, so no changes are needed to the docs.

As things stand at this moment, we would still be overwritting `$args` in the function via the call to `func_get_args()`, but that's ok for now, we'll get to that in step 3.



**Step 3: modernize the return.**

Now, let's look at the part of the function which is returning the result:
{{{#!php
<?php
	$args = func_get_args();

	return call_user_func_array( array( $current_user, 'has_cap' ), $args );
}}}

`call_user_func_array()` is used here as `$args` would contain a variable number of arguments and prior to PHP 5.6, there was no other way to pass those on to another function which expected multiple arguments.

However, PHP 5.6 also introduced [https://www.php.net/manual/en/migration56.new-features.php#migration56.new-features.splat argument unpacking using the spread operator].

Now suddenly, the call to the badly performing `call_user_func_array()` is no longer necessary and we can call `$current_user->has_cap()` directly, unpacking the variadic `$args` in the function call:

{{{#!php
<?php
	return $current_user->has_cap( $capability, ...$args );
}}}


So, that's how we get to the actual patch.

All together, this patch gets rid of four redundant function calls, three of which were calls to functions with a bad reputation for performance.

So, even though small, this patch should give WP a very tiny performance boost.


**Unit tests**

There are numerous tests in the [https://core.trac.wordpress.org/browser/trunk/tests/phpunit/tests/user/capabilities.php `Tests_User_Capabilities`] class covering this change already.

All of these tests still pass after this change.

And once I've uploaded this patch, I will start a Travis run just to make sure and quieten any nerves anyone may have about this patch.

/cc @pento"	task (blessed)	closed	normal	5.3	Role/Capability	trunk	normal	fixed	has-patch has-unit-tests has-dev-note		performance, coding-standards	
