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

Utilize composer min-php version to narrow PHP_VERSION_ID #2968

Open
wants to merge 19 commits into
base: 1.10.x
Choose a base branch
from

Conversation

staabm
Copy link
Contributor

@staabm staabm commented Mar 13, 2024

idea is to catch errors like Roave/BetterReflection#1406 (comment) in which bogus conditions like if (PHP_VERSION_ID >= 80100) {} have been used in tests.

it's a bug in the linked case, because the project itself only supports "php": "~8.2.0 || ~8.3.2",.
Since CI only is running against in composer.json declared supported versions this error was not spotted before.

Copy link
Member

@ondrejmirtes ondrejmirtes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do the upper bound too - so that we know ^8.1 cannot be 9.

@staabm
Copy link
Contributor Author

staabm commented Mar 13, 2024

@ondrejmirtes what do you think about all these

Comparison operation "<" between int<80100, max> and 80100 is always false.

errors? should we ignore them via phpstan.neon or should we add e.g. a feature flag, so we can disable the composer based min/max-php version?

@ondrejmirtes
Copy link
Member

It's not really generally usable. In PHPStan and many other apps, the constraint in composer.json does nor say anything about production environment, or can be outdated.

It could be:

  • On in bleeding edge
  • But at the same time there should be a way to turn it off, or make it configurable manually, like reading the range from phpstan.neon instead of composer.json. phpVersion behaves similarly, when it's null, we try to detect it.

@clxmstaab clxmstaab force-pushed the min-php branch 2 times, most recently from 8c64205 to 6dbb9d1 Compare March 13, 2024 15:39
@@ -671,7 +671,7 @@ public function testBug8068(): void

public function testBug6243(): void
{
if (PHP_VERSION_ID < 704000) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

found a bug in a pre-existing test

Comment on lines 40 to 41
$config['parameters']['minPhpVersion'] = 70100;
$config['parameters']['maxPhpVersion'] = 90000;
Copy link
Contributor Author

@staabm staabm Mar 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I put the min/max php version here, so we have a fixed upper/lower bound in phpstan-src, but all projects per default still use composer.json based auto-php-version bounds. I think even projects using bleeding-edge would benefit from automatic php version bounds.

the case that projects need to opt-out from this check will be rare I guess - but is possible via the new phpstan.neon parameters by defining custom versions

@staabm
Copy link
Contributor Author

staabm commented Mar 13, 2024

I think the errors we see in CI make sense. not sure what we can/should do about them.

it make sense to check for php-versions smaller then the composer.json declared supported ones, to be super safe.
maybe I should use composer-min-version - 1 as a lower bound?

edit: did just that with 0d398ab

@staabm staabm marked this pull request as ready for review March 13, 2024 16:06
@phpstan-bot
Copy link
Collaborator

This pull request has been marked as ready for review.

// allow checks with < below lower bound to prevent errors like
// 'Comparison operation "<" between int<70205, 90000> and 70205 is always false.'
if ($minVersion !== null) {
$this->minVersion = new PhpVersion($minVersion->getVersionId() - 1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This subtraction seems very dodgy to me. If I get it correctly this is to fix warnings where if (PHP_VERSION_ID < 70100) where I have a require of php >=7.1 for example. But why should it not warn? Because clearly per the requirement the code should not be allowed to run with a version lower than 70100.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reading your comment above:

it make sense to check for php-versions smaller then the composer.json declared supported ones, to be super safe.

Yes it may make sense in some cases, but then you want to explicitly override PHPStan and add this in the baseline IMO. In most cases I'd think you will want PHPStan to tell you that this check can be removed when you bump your PHP version requirement, which suddenly would not work anymore here due to the -1.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

relevant examples from previous CI failures are

I am fine with leaving this error and let the projects put them into a baseline, but my thinking was, that it might be pretty common that code tries to detect whether it is invoked from a not supported php-version (so whether PHP_VERSION is below the lower limit of composer.json requirements)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right yeah those two examples for Composer are definitely things I'd be ok ignoring if it gets me visibility on other things I forgot to delete.

@staabm staabm force-pushed the min-php branch 2 times, most recently from 982b705 to eb63e2a Compare March 18, 2024 08:09
@clxmstaab clxmstaab force-pushed the min-php branch 2 times, most recently from e7c38fc to 0a2f82f Compare March 18, 2024 09:33
@staabm staabm marked this pull request as draft March 18, 2024 09:39
@staabm staabm marked this pull request as ready for review March 18, 2024 10:03
@phpstan-bot
Copy link
Collaborator

This pull request has been marked as ready for review.

@staabm
Copy link
Contributor Author

staabm commented Mar 22, 2024

@ondrejmirtes keeping this one up2date is a bit cumbersome, because of the added composer dependency (and the conflicts I need to resolve on every other dependency update).

would be great if you could find the time to move it forward.

Copy link
Member

@ondrejmirtes ondrejmirtes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some thoughts about this PR:

  1. There are more constants related to PHP versions: https://www.php.net/manual/en/reserved.constants.php
  2. To be really useful, this should also influence version_compare: https://www.php.net/manual/en/function.version-compare.php A dynamic return type extension would be sufficient.
  3. I'd like phpVersion to be either: null, a single number, or a structure with min/max

If it's null, resolve it to a single number in PHPStan 1.x (according to config.platform.php in composer.json), and to min/max structure with bleeding edge (according to require.php in composer.json).

If it's a single number, keep today's behaviour. Meaning PHP_VERSION_ID is not going to be limited.

If it's min/max, clamp PHP_VERSION_ID and other constants to be an IntegerRangeType.

Also we should have some kind of warning if the values don't make sense. max should be >= min.

@staabm
Copy link
Contributor Author

staabm commented Mar 24, 2024

thanks for the feedback.

If it's null, resolve it to a single number in PHPStan 1.x (according to config.platform.php in composer.json), and to min/max structure with bleeding edge (according to require.php in composer.json).

If it's a single number, keep today's behaviour. Meaning PHP_VERSION_ID is not going to be limited.

If it's min/max, clamp PHP_VERSION_ID and other constants to be an IntegerRangeType.

this means in case of a configured min/max version, we don't have a concrete version anymore in PhpVersion.
so all the support-methods don't work like they do today. since PhpVersion is tagged @api I cannot change it to return a Trinary..

public function supportsNullCoalesceAssign(): bool
{
return $this->versionId >= 70400;
}

@ondrejmirtes
Copy link
Member

That's right. Changing all these methods to a TrinaryLogic would be a costly refactoring that would eventually lead to ReflectionClass::hasClass() also returning TrinaryLogic. I'd like that but not at this point.

Please try using the min value as the origin for these methods to decide whether to return true or false.

@ondrejmirtes
Copy link
Member

If that's not going to work for some reason then I'm not interested in this PR at this point, sorry. When investing in an area we need to do something that makes sense, not just a minimal amount of work that would change the interpretation of a single constant.

@staabm
Copy link
Contributor Author

staabm commented Mar 24, 2024

Sure, lets see how it goes.

Alternatively/Additionally I will look into a narrowed PhpVersion based on scope like we brainstormed in phpstan/phpstan#4212 (reply in thread)

@staabm staabm marked this pull request as draft March 24, 2024 10:20
@staabm staabm marked this pull request as ready for review March 24, 2024 21:18
@phpstan-bot
Copy link
Collaborator

This pull request has been marked as ready for review.

@staabm
Copy link
Contributor Author

staabm commented Mar 24, 2024

I think all the feedback is adressed

@clxmstaab clxmstaab force-pushed the min-php branch 2 times, most recently from 1279561 to 764bb38 Compare March 27, 2024 08:25
Comment on lines +3 to +5
\PHPStan\Testing\assertType('int<80099, 80299>', PHP_VERSION_ID);
\PHPStan\Testing\assertType('8', PHP_MAJOR_VERSION);
\PHPStan\Testing\assertType('int<0, 2>', PHP_MINOR_VERSION);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
\PHPStan\Testing\assertType('int<80099, 80299>', PHP_VERSION_ID);
\PHPStan\Testing\assertType('8', PHP_MAJOR_VERSION);
\PHPStan\Testing\assertType('int<0, 2>', PHP_MINOR_VERSION);
\PHPStan\Testing\assertType('int<80100, 80299>', PHP_VERSION_ID);
\PHPStan\Testing\assertType('8', PHP_MAJOR_VERSION);
\PHPStan\Testing\assertType('int<1, 2>', PHP_MINOR_VERSION);

AFAK PHP_VERSION_ID starts with the major/minor even if run on alpha release

PHP_MINOR_VERSION should be narrowed if PHP_MAJOR_VERSION is one constant number

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I saw it. But I do not support it. The reason is composer already check this during runtime and if the check is really, really wanted, the user should ignore that error instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants