Skip to content

PHP 7.4 Warning for string to number comparisons that may change#3917

Closed
nikic wants to merge 2 commits into
php:PHP-7.4from
nikic:string-comparison-7.4
Closed

PHP 7.4 Warning for string to number comparisons that may change#3917
nikic wants to merge 2 commits into
php:PHP-7.4from
nikic:string-comparison-7.4

Conversation

@nikic

@nikic nikic commented Mar 4, 2019

Copy link
Copy Markdown
Member

Companion to #3886 for RFC https://wiki.php.net/rfc/string_to_number_comparison. This implements a warning in PHP 7.4 that is thrown if the comparison result will be different in PHP 8 (if the change is accepted). For now this is just an unconditional warning and also prints the compared values.

@nikic nikic changed the title String comparison 7.4 PHP 7.4 Warning for string to number comparisons that may change Mar 4, 2019
@nikic nikic added the RFC label Mar 4, 2019
@nikic

nikic commented Mar 4, 2019

Copy link
Copy Markdown
Member Author

Results for running this on the Laravel test suite:

1) Illuminate\Tests\Database\DatabaseEloquentBelongsToTest::testIdsInEagerConstraintsCanBeZero
Result of comparison between 0 and "foreign.value" will change (0 to -1)

/home/nikic/laravel/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php:140
/home/nikic/laravel/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php:118
/home/nikic/laravel/tests/Database/DatabaseEloquentBelongsToTest.php:96

2) Illuminate\Tests\Support\SupportCollectionTest::testSearchReturnsFalseWhenItemIsNotFound
ErrorException: Result of comparison between 1 and "bar" will change (1 to -1)

/home/nikic/laravel/tests/Support/SupportCollectionTest.php:2113
/home/nikic/laravel/src/Illuminate/Support/Collection.php:1459
/home/nikic/laravel/tests/Support/SupportCollectionTest.php:2114
  1. is part of this sort() call: https://github.com/laravel/framework/blob/d0a33d4a398f2bd23c2689aac473a3453ece76cc/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php#L140 I can't really tell whether or not the different sort order would be a problem.

  2. is due to https://github.com/laravel/framework/blob/d0a33d4a398f2bd23c2689aac473a3453ece76cc/tests/Support/SupportCollectionTest.php#L2113, which uses a $value < 1 && is_numeric($value) check. This warning is ultimately a false positive due to the is_numeric() check, though it would be better to do that check first.

@nikic

nikic commented Mar 4, 2019

Copy link
Copy Markdown
Member Author

Results for running this against pear-core tests (as a representative of a much older codebase):

/home/nikic/pear-core/tests/PEAR_Command_Install/install/test_bug18102.phpt:
001- tests done
001+ Warning: Result of comparison between 0 and "*" will change (0 to 1) in /home/nikic/pear-core/PEAR.php on line 545
002+ tests done

/home/nikic/pear-core/tests/PEAR_Command_Package/package-validate/test.phpt:
001- tests done
001+ Warning: Result of comparison between 255 and "package.xml" will change (1 to -1) in /home/nikic/pear-core/PEAR/PackageFile.php on line 318
002+ tests done
  1. is due to https://github.com/pear/pear-core/blob/2e88e8707cdf666eec647b1855d69bcd0ef75bd9/PEAR.php#L545. The 0 that is being compared against is most likely PEAR_INSTALLER_FAILED, which is an error code. This looks like a bug to me, because it ends up not testing the expected error code. This should use === "*".

  2. is due to https://github.com/pear/pear-core/blob/master/PEAR/PackageFile.php#L318, which does a strlen($file < 255) check. This is obviously a bug and should be strlen($file) < 255.

@nikic

nikic commented Mar 4, 2019

Copy link
Copy Markdown
Member Author

Results for running against symfony tests (I get many baseline errors, but this is the only new one):

4) Symfony\Component\Translation\Tests\IntervalTest::testTest with data set #0 (true, 3, '{1,2, 3 ,4}')
Result of comparison between 3 and " 3 " will change (0 to 1)

/home/nikic/symfony/src/Symfony/Component/Translation/Interval.php:61
/home/nikic/symfony/src/Symfony/Component/Translation/Tests/IntervalTest.php:27

This is because trailing whitespace is not allowed in numeric strings. Something that's the case right now, but we should change this prior to making these comparison semantics changes.

@nikic

nikic commented Jul 2, 2020

Copy link
Copy Markdown
Member Author

As PHP 7.4 has been released long ago, this PR is no longer relevant...

@nikic nikic closed this Jul 2, 2020
@nikic nikic reopened this Jul 15, 2020
nikic added 2 commits July 15, 2020 11:04
While the comparison result changes, the equality comparison is not
going to care about it in the end.
@nikic nikic force-pushed the string-comparison-7.4 branch from 38493a0 to b2350cc Compare July 15, 2020 09:08
@nikic

nikic commented Jul 15, 2020

Copy link
Copy Markdown
Member Author

Reopened this to rebase, closing again...

@nikic nikic closed this Jul 15, 2020
@brendt

brendt commented Jul 16, 2020

Copy link
Copy Markdown

Thanks, I did some tests with it on one of our largest projects, and no warnings were shown 👌

@kamazee

kamazee commented Dec 8, 2020

Copy link
Copy Markdown
Contributor

Did this go anywhere? Something like deprecation message on comparisons result of which will change in 8.0 would help a lot when migrating legacy codebase to 8.0.
As I understand, applying this patch privately and recompiling PHP is the only way to achieve what was the point of this PR, right?

In particular, I'm worried about "" == 0

@rainbow-alex

Copy link
Copy Markdown

For anyone still testing their code against this: it seems that opcache sometimes prevents the warning from being raised, so be sure to disable opcache.

For example: with opcache enabled I only get one warning for this code instead of two:

function main()
{
	var_dump(0 == "");
	$a = 0;
	$b = "";
	var_dump($a == $b);
}

main();

@orklah

orklah commented Jan 23, 2021

Copy link
Copy Markdown

If this can help, I made a Psalm plugin for such cases: https://github.com/orklah/psalm-insane-comparison . It's not failproof and it depends on your project type coverage, but it will find the obvious cases

@kamazee

kamazee commented Jan 23, 2021

Copy link
Copy Markdown
Contributor

While this might work for some cases, I don't think static analysis is capable of covering such cases in general because sometimes it's hard or even impossible to derive a type statically as it might depend on runtime settings things such as, for example, PDO::ATTR_STRINGIFY_FETCHES.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants