Skip to content

Conversation

@jrfnl
Copy link
Member

@jrfnl jrfnl commented Mar 17, 2024

This PR replaces PR #1669


FunctionDeclarations/RemovedOptionalBeforeRequiredParam: test with uppercase null

No functional changes needed, this just is an extra safeguard that the sniff handles this correctly.

FunctionDeclarations/RemovedOptionalBeforeRequiredParam: add extra tests/constant expressions

Add some extra tests with null in the default value, but not as a stand-alone value, but as part of a constant expression.

PHP itself will only evaluate constant expressions at runtime (when the function is called), not at compile time (when the deprecation is flagged).
In practice, this means that a default value containing a constant expression which evaluates to null will always be flagged as deprecated by PHP if the parameter is before a required one and that the exception for typed properties with a null default does not apply to constant expressions.

This means that the sniffs should also disregard any null token within a constant expression, as the only thing that's relevant is that case, is that there is a default value.
Given that, the sniff is handling this correctly as-is.

Also see: php/php-src#13752

FunctionDeclarations/RemovedOptionalBeforeRequiredParam: use named test cases

... in the false positives data provider.

This will make some changes in follow-up commits easier.

FunctionDeclarations/RemovedOptionalBeforeRequiredParam: flag the optional param, not the required param

Originally, the sniff would walk from the first param to the last, keeping track of whether an optional parameter has been seen and flag any required parameter found after it.

This commit changes the logic in the sniff to flag the actual issue with higher precision, by walking from the last parameter back to the first, keeping track of seen required parameters and flagging any optional parameters found before these.

It also updates the error message to more closely match the error message used in PHP itself.
PHP 8.0 would flag issues with "Deprecated: Required parameter $b follows optional parameter $a".
As of PHP 8.1, the message was changed to read: "Deprecated: Optional parameter $a declared before required parameter $b is implicitly treated as a required parameter".

FunctionDeclarations/RemovedOptionalBeforeRequiredParam: add tests with PHP 8.1 new in initializers

PHP 8.1 introduced the ability to use new in initializers. This now opens up the possibility that null is passed to an initializer.

In practice though, this has no impact on the sniff as the "new object" is a default value making the parameter optional, so should still be flagged when used before a required parameter.

FunctionDeclarations/RemovedOptionalBeforeRequiredParam: flag nullable types / PHP 8.1

The recent RFC proposing to deprecate implicit nullable types brough an oversight in the PHPCompatibility.FunctionDeclarations.RemovedOptionalBeforeRequiredParam sniff to my attention.

To quote the RFC:

Even though signatures which contain an optional parameter before a required one were deprecated in PHP 8.0, the case of implicitly nullable types was left alone at that time due to BC concerns. This exclusion caused some bugs in the detection of which signatures should emit the deprecation notice. Indeed, the following signature only emits a deprecation as of PHP 8.1:

function bar(T1 $a, ?T2 $b = null, T3 $c) {}

At the time of writing this sniff this additional deprecation notice was not yet in place and was therefore not taken into account.

This commit updates the sniff to also throw deprecation notices for optional parameters before required ones, where the default value is null and the type is nullable.

Includes unit tests safeguarding the fix.

Ref: php/php-src@c939bd2

FunctionDeclarations/RemovedOptionalBeforeRequiredParam: flag union types with null / PHP 8.3

The recent RFC proposing to deprecate implicit nullable types brough an oversight in the PHPCompatibility.FunctionDeclarations.RemovedOptionalBeforeRequiredParam sniff to my attention.

To quote the RFC:

Even though signatures which contain an optional parameter before a required one were deprecated in PHP 8.0, the case of implicitly nullable types was left alone at that time due to BC concerns. This exclusion caused some bugs in the detection of which signatures should emit the deprecation notice.

And the signature that uses the generalized union type signature:

function test(T1 $a, T2|null $b = null, T3 $c) {}

only emits the deprecation notice properly as of PHP 8.3.

At the time of writing this sniff this additional deprecation notice was not yet in place and was therefore not taken into account.

This commit updates the sniff to also throw deprecation notices for optional parameters before required ones, where the default value is null and the type is null or a union/DNF type which includes null.

Includes unit tests safeguarding the fix.

Refs:

FunctionDeclarations/RemovedOptionalBeforeRequiredParam: add documentation

jrfnl added 8 commits March 19, 2024 02:04
…percase null

No functional changes needed, this just is an extra safeguard that the sniff handles this correctly.
…sts/constant expressions

Add some extra tests with `null` in the default value, but not as a stand-alone value, but as part of a constant expression.

PHP itself will only evaluate constant expressions at runtime (when the function is called), not at compile time (when the deprecation is flagged).
In practice, this means that a default value containing a constant expression which evaluates to `null` will always be flagged as deprecated by PHP if the parameter is before a required one and that the exception for typed properties with a `null` default does not apply to constant expressions.

This means that the sniffs should also disregard any `null` token within a constant expression, as the only thing that's relevant is that case, is that there is a default value.
Given that, the sniff is handling this correctly as-is.

Also see: php/php-src#13752
…st cases

... in the false positives data provider.

This will make some changes in follow-up commits easier.
…ional param, not the required param

Originally, the sniff would walk from the first param to the last, keeping track of whether an optional parameter has been seen and flag any required parameter found after it.

This commit changes the logic in the sniff to flag the actual issue with higher precision, by walking from the last parameter back to the first, keeping track of seen required parameters and flagging any optional parameters found before these.

It also updates the error message to more closely match the error message used in PHP itself.
PHP 8.0 would flag issues with "Deprecated: Required parameter $b follows optional parameter $a".
As of PHP 8.1, the message was changed to read: "Deprecated: Optional parameter $a declared before required parameter $b is implicitly treated as a required parameter".
…th PHP 8.1 new in initializers

PHP 8.1 introduced the ability to use `new` in initializers. This now opens up the possibility that `null` is passed to an initializer.

In practice though, this has no impact on the sniff as the "`new` object" is a default value making the parameter optional, so should still be flagged when used before a required parameter.
…e types / PHP 8.1

The [recent RFC proposing to deprecate implicit nullable types](https://wiki.php.net/rfc/deprecate-implicitly-nullable-types) brough an oversight in the `PHPCompatibility.FunctionDeclarations.RemovedOptionalBeforeRequiredParam` sniff to my attention.

To quote [the RFC](https://wiki.php.net/rfc/deprecate-implicitly-nullable-types):
> Even though signatures which contain an optional parameter before a required one were deprecated in PHP 8.0, the case of implicitly nullable types was left alone at that time due to BC concerns. This exclusion caused some bugs in the detection of which signatures should emit the deprecation notice. Indeed, the following signature only emits a deprecation as of PHP 8.1:
>
> `function bar(T1 $a, ?T2 $b = null, T3 $c) {}`

At the time of writing this sniff this additional deprecation notice was not yet in place and was therefore not taken into account.

This commit updates the sniff to _also_ throw deprecation notices for optional parameters before required ones, where the default value is `null` and the type is nullable.

Includes unit tests safeguarding the fix.

Ref: php/php-src@c939bd2
…ypes with null / PHP 8.3

The [recent RFC proposing to deprecate implicit nullable types](https://wiki.php.net/rfc/deprecate-implicitly-nullable-types) brough an oversight in the `PHPCompatibility.FunctionDeclarations.RemovedOptionalBeforeRequiredParam` sniff to my attention.

To quote [the RFC](https://wiki.php.net/rfc/deprecate-implicitly-nullable-types):
> Even though signatures which contain an optional parameter before a required one were deprecated in PHP 8.0, the case of implicitly nullable types was left alone at that time due to BC concerns. This exclusion caused some bugs in the detection of which signatures should emit the deprecation notice.
> <snip>
> And the signature that uses the generalized union type signature:
>
> `function test(T1 $a, T2|null $b = null, T3 $c) {}`
>
> only emits the deprecation notice properly as of PHP 8.3.

At the time of writing this sniff this additional deprecation notice was not yet in place and was therefore not taken into account.

This commit updates the sniff to _also_ throw deprecation notices for optional parameters before required ones, where the default value is `null` and the type is `null` or a union/DNF type which includes `null`.

Includes unit tests safeguarding the fix.

Refs:
* php/php-src 11488
* php/php-src 11497
* php/php-src@68ef393
@jrfnl jrfnl force-pushed the feature/removedoptionalbeforerequiredparam-review-and-bugfix branch from 6bbbd4b to 34be846 Compare March 19, 2024 01:07
@jrfnl
Copy link
Member Author

jrfnl commented Mar 19, 2024

Rebased and updated the commit message for the "FunctionDeclarations/RemovedOptionalBeforeRequiredParam: add extra tests/constant expressions" commit to document the PHP native behaviour better.

@wimg wimg merged commit cc959ab into develop Mar 31, 2024
@wimg wimg deleted the feature/removedoptionalbeforerequiredparam-review-and-bugfix branch March 31, 2024 23:58
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.

3 participants