-
-
Notifications
You must be signed in to change notification settings - Fork 480
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add function call parameter related utility functions and abstract class #815
Conversation
I initially introduced these functions in the PHPCompatibility standard were they are also individually unit tested. They have been in use there for a number of months and proven useful & accurate.
This extends the `WordPress_AbstractFunctionRestrictionsSniff` class for the yes/no function call determination, retrieves the parameters used in a function call and then passes processing on to the child class. The child class is expected to implement a `process_parameters()` method to handle the actual testing of parameters. Optionally a `process_no_parameters()` method can be added to the child class to handle cases where parameters are expected, but not found. The abstract expects a `$target_functions` array, but is without opinion about how that array should look, except for the requirement that the top level array keys are the function names. Further requirements of the array are not needed as the processing of the parameters is done in the child class, allowing for great flexibility in potential use of this class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you very much for this.This will be a great help! This fixes #745
One thought that can to me is what would happen if one of the parameters that we were checking was an anonymous function. A common place where anonymous functions are used are hooks.
* | ||
* @var array The only requirement for this array is that the top level | ||
* array keys are the names of the functions you're looking for. | ||
* Other than that, the array can have arbitrary content depending on your needs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the text not need to be all on the same height? e.g.
/**
* @var array The only requirement for this array is that the top level
* array keys are the names of the functions you're looking for.
* Other than that, the array can have arbitrary content depending
* on your needs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I second this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
// Ignore anything within short array definition brackets. | ||
if ( 'T_OPEN_SHORT_ARRAY' === $this->tokens[ $next_comma ]['type'] | ||
&& ( isset( $this->tokens[ $next_comma ]['bracket_opener'] ) | ||
&& $this->tokens[ $next_comma ]['bracket_opener'] === $next_comma ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason why there is an extra tab before the code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes: nested parenthesis.
* @return void | ||
*/ | ||
public function process_no_parameters( $stackPtr, $group_name, $matched_content ) { | ||
$this->phpcsFile->addError( 'Missing arguments to %s.', $stackPtr, 'MissingArguments', array( $matched_content ) ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need this as if there are no parameters then there will be a PHP error. #770 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do need this.
By far not all function calls have required parameters, so a function call without parameters can be perfectly valid code, no syntax errors, but might still need to throw an error under certain rules.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The three functions that we are checking have required parameters. in_array
, array_search
and array_keys
. Sorry I did not mean generally, just for this check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh sorry, I was thinking the comment was about the abstract.
And true, in this case "no parameters" would also result in a PHP error, though not one which would be picked up by the Generic.PHP.Syntax
sniff (not a parse error).
I added the method and the error message in this case to maintain backward compatibility. The same message was already being thrown by this sniff and I saw no compelling reason to remove it.
That works just fine, you will receive the start and end parameter and the raw content, no problem ;-) More in-depth: The functions check for parenthesis at the correct nesting level and will skip over everything which is not at the right nesting level, so an anonymous function as a parameter will be returned and treated as one parameter. And before you ask: The methods don't deal with parameters passed to anonymous functions, but don't need to either as that is a function declaration and you can use the PHPCS native |
* | ||
* @param int $stackPtr The position of the function call token. | ||
* | ||
* @return array |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we document the output too? Perhaps with something like:
/**
* @return array {
* Array of parameters. Empty array if there are no parameters.
*
* @type int $position Position of the parameter. {
* @type int $start Start position of the call token.
* @type int $end End position of the call token.
* @type int $raw Raw parameter content.
* }
* }
or
/**
* @return array {
* Array of parameters. Empty array if there are no parameters.
*
* @type int $position => { Position of the parameter.
* @type int $start Start position of the call token.
* @type int $end End position of the call token.
* @type int $raw Raw parameter content.
* }
* }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It already was documented a bit further up in the function documentation, but I've adjusted the format to a variant of what you suggested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💯 I've created similar functions before, though not as robust, and I know that they can be very useful.
* | ||
* @var array The only requirement for this array is that the top level | ||
* array keys are the names of the functions you're looking for. | ||
* Other than that, the array can have arbitrary content depending on your needs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I second this.
Now #795 has been merged, it was possible to create an abstract function parameter class which builds upon the logic for determining function calls already contained in
WordPress_AbstractFunctionRestrictionsSniff
.This PR introduces the abstract and a number of related utility functions.
Utility functions
I initially introduced these utility functions in the PHPCompatibility standard were they are also individually unit tested.
They have been in use there for a number of months and proven useful & accurate.
The functions are:
does_function_call_have_parameters( $stackPtr )
- returns boolget_function_call_parameter_count( $stackPtr )
- returns intget_function_call_parameters( $stackPtr )
- returns array, key: 1-indexed parameter position, value: array withstart
- int stack pointer of param start position,end
- int stack pointer of param end position andraw
- trimmed raw content for the passed parameterget_function_call_parameter( $stackPtr, $param_offset )
- returns array or false if no parameter was found at the specified offsetThe functions expect to be passed a
T_STRING
stack pointer to a function call.And while the function name might not indicate this, each of these functions can also be used with array stack pointers (
T_ARRAY
,T_OPEN_SHORT_ARRAY
). This is a feature which was introduced after the initial naming & merge of the functions and the function documentation reflects this.It is my intention to introduce these functions upstream in PHPCS itself at some point in the future.
New
WordPress_AbstractFunctionParameterSniff
classThe new
WordPress_AbstractFunctionParameterSniff
extends theWordPress_AbstractFunctionRestrictionsSniff
class for the yes/no function call determination, retrieves the parameters used by the targetted function call using the new utility functions and then passes processing on to the child class.The child class is expected to implement a
process_parameters()
method to handle the actual testing of parameters.Optionally a
process_no_parameters()
method can be added to the child class to handle cases where parameters are expected, but not found.The abstract expects a
$target_functions
array, but is without opinion about how that array should look, except for the requirement that the top level array keys are the function names.Further requirements of the array are not needed as the processing of the parameters is done in the child class, allowing for great flexibility in potential use of this class.
Start using the abstract
As a last step - and to prove that the same functionality is maintained, and in some cases improved by the new abstract - I've refactored three existing sniffs which were prime candidates (duplicate logic and such) to start using the new
WordPress_AbstractFunctionParameterSniff
.Fixes #745