Skip to content
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

PHP 8.1 | Utils\PassedParameters: change named param implementation/named params after variadic #383

Conversation

jrfnl
Copy link
Member

@jrfnl jrfnl commented Oct 23, 2022

Follow up on #235 and #361.

As of PHP 8.1, named parameters after argument unpacking in function calls is allowed. This has implications for how to retrieve a parameter from the parameter stack in the PassedParameters::getParameterFromStack() method and exposes a pre-existing short-coming in the method as argument unpacking was not taken into account.

While argument unpacking will always throw the retrieval of a specific parameter off if that specific parameter is one of the parameters being unpacked, the method can still be improved to handle this better in the context of named parameters.

To make this more straight-forward, I'm changing the implementation for support for named parameters in the PassedParameters::getParameters() method.

Previously (but so far unreleased), the return array for named parameters would contain three extra keys: name_start, name_end and name and the top-level index for the parameter would be based on the position of the parameter in the function call.

As support for PHPCS < 3.7.1 has been dropped, the name_start and name_end are no longer relevant as the tokenization of the names will be consistent and will always be T_PARAM_NAME - T_COLON. (This was previously not the case as prior to PHPCS 3.6.0, the tokenization of parameter labels could vary based on the label and the spacing used). The name_start and name_end keys are now being replaced by a name_token key pointing to the T_PARAM_NAME token.

On top of that, for named parameters, the position in the function call is irrelevant, so having the position as the top-level index is redundant.

So... this commit makes the following changes:

  1. PassedParameters::getParameters(): the name_start and name_end keys have been removed and instead a name_token key will be added. Note: the name key in the parameter sub-array will also still be set as both the PassedParameters::getParameter() method as well as the PassedParameters::getParameterFromStack() method will return only the parameter specific sub-array and what with a sniff potentially passing multiple parameter names, it is still useful to know which one was matched.
  2. PassedParameters::getParameters(): the key for the parameter will now be either its position or the parameter name. This does mean that the behaviour for function calls passing duplicate named parameters has changed. The first parameter using the name will be in the top-level array by name, the second parameter using the same name, will be in the array using their position as the key (as the duplicate name would otherwise overwrite the first entry). As duplicate parameter names being used in a function call would result in an Error exception in PHP anyway, I'm not too concerned about this.
  3. PassedParameters::getParameterFromStack() will now attempt to find a named parameter first and only look for the positional variant after.

Includes:

  • An additional test for the PassedParameters::getParameterFromStack() method to verify that retrieving a named parameter after a variadic parameter is handled correctly.
  • An additional test for the PassedParameters::getParameterCount() method to safeguard that duplicate parameter names will still result in a correct parameter count.
  • Updating the test expectations in various test classes.
  • A minor ruleset tweak to exempt the GetParametersNamedTest class from the Universal.Arrays.MixedArrayKeyTypes sniff as the return value of PassedParameters::getParameters() may now contain mixed array keys.
  • Removing an unused use statement (follow up after Follow up on version drop/ remove some more code #369).

Note: it will still be the responsibility of individual sniffs to take argument unpacking in function calls into account when examining parameters.

Refs:

…amed params after variadic

Follow up on 235 and 361.

As of PHP 8.1, named parameters after argument unpacking in function calls is allowed. This has implications for how to retrieve a parameter from the parameter stack in the `PassedParameters::getParameterFromStack()` method and exposes a pre-existing short-coming in the method as argument unpacking was not taken into account.

While argument unpacking will always throw the retrieval of a specific parameter off if that specific parameter is one of the parameters being unpacked, the method can still be improved to handle this better in the context of named parameters.

To make this more straight-forward, I'm changing the implementation for support for named parameters in the `PassedParameters::getParameters()` method.

Previously (but so far unreleased), the return array for named parameters would contain three extra keys: `name_start`, `name_end` and `name` and the top-level index for the parameter would be based on the position of the parameter in the function call.

As support for PHPCS < 3.7.1 has been dropped, the `name_start` and `name_end` are no longer relevant as the tokenization of the names will be consistent and will always be `T_PARAM_NAME` - `T_COLON`.
(This was previously not the case as prior to PHPCS 3.6.0, the tokenization of parameter labels could vary based on the label and the spacing used).
The `name_start` and `name_end` keys are now being replaced by a `name_token` key pointing to the `T_PARAM_NAME` token.

On top of that, for named parameters, the position in the function call is irrelevant, so having the position as the top-level index is redundant.

So... this commit makes the following changes:
1. `PassedParameters::getParameters()`: the `name_start` and `name_end` keys have been removed and instead a `name_token` key will be added.
    Note: the `name` key in the parameter sub-array _will_ also still be set as both the `PassedParameters::getParameter()` method as well as the `PassedParameters::getParameterFromStack()` method will return only the parameter specific sub-array and what with a sniff potentially passing multiple parameter names, it is still useful to know which one was matched.
2. `PassedParameters::getParameters()`: the _key_ for the parameter will now be either its position or the parameter name.
    This does mean that the behaviour for function calls passing _duplicate_ named parameters has changed. The first parameter using the name will be in the top-level array by name, the second parameter using the same name, will be in the array using their position as the key (as the duplicate name would otherwise overwrite the first entry).
    As duplicate parameter names being used in a function call would result in an `Error` exception in PHP anyway, I'm not too concerned about this.
3. `PassedParameters::getParameterFromStack()` will now attempt to find a named parameter first and only look for the positional variant after.

Includes:
* An additional test for the `PassedParameters::getParameterFromStack()` method to verify that retrieving a named parameter after a variadic parameter is handled correctly.
* An additional test for the `PassedParameters::getParameterCount()` method to safeguard that duplicate parameter names will still result in a correct parameter count.
* Updating the test expectations in various test classes.
* A minor ruleset tweak to exempt the `GetParametersNamedTest` class from the `Universal.Arrays.MixedArrayKeyTypes` sniff as the return value of `PassedParameters::getParameters()` may now contain mixed array keys.
* Removing an unused `use` statement (follow up after 369).

Note: it will still be the responsibility of individual sniffs to take argument unpacking in function calls into account when examining parameters.

Refs:
* https://www.php.net/manual/en/migration81.new-features.php#migration81.new-features.core.named-arg-after-unpack
@jrfnl jrfnl force-pushed the php-8.1/passedparameters-getfromstack-handle-named-after-variadic branch from 264e3ea to 0effc58 Compare October 23, 2022 03:39
@jrfnl jrfnl merged commit f89d144 into develop Oct 23, 2022
@jrfnl jrfnl deleted the php-8.1/passedparameters-getfromstack-handle-named-after-variadic branch October 23, 2022 03:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant