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

Only allow loose comparison with numeric operands #40

Open
jasny opened this issue Oct 5, 2018 · 3 comments
Open

Only allow loose comparison with numeric operands #40

jasny opened this issue Oct 5, 2018 · 3 comments

Comments

@jasny
Copy link

jasny commented Oct 5, 2018

Similar to arithmetic operators (+/-/*///**/%), loose comparison operators should only be used for numeric values. This is true for ==, !=, <, >, <=, >= and <=>.

Using any of these operators for non-numeric values may lead to unexpected results.

The option to disallow == and != completely doesn't cover the full problem as other comparison operators are still allowed and might give unexpected result. It also disallows cases where you do want to use == because you're comparing numbers.

Good

42 == 42.0 // true
42 == "42" // true
42 == "4.2e1" // true
42 < "0xf1" // true

Bad

// convert to int, I guess
1000 >= "42 bytes" // true
(int)"42 bytes" // 42

// but not always :-(
(int)"4.2e1 bytes" // 42
1000 >= "4.2e1 bytes" // false ??

Universal rules of logic state that if a > b and b > c than a > c

$a = '42';
$b = 10;
$c = '9 dwarfs';

$a > $b // true
$b > $c // true
$a > $c // false ??

The spaceship operator should also not be used for strings.

function cmp1(string $x, string $y) {
    return $x <=> $y;
}

function cmp2(string $x, string $y) {
    return ($x . 'Foo') <=> ($y . 'Foo');
}

// Both functions should do the same, but...
cmp1("55", "5.5e1"); // 0
cmp2("55", "5.5e1"); // 1

The logic behind wether or not a string is converted to a number is just to complex. It's party explained in the manual, but that's not conclusive.

For strings you SHOULD always use === or strcmp.

While == could be useful to compare objects, the strange behaviour on strings makes this too dangerous.

$one = (object)['a' => 0];
$two = (object)['a' => '0.0'];
$three = (object)['a' => 'bar'];

$one == $two; // true
$one == $three; // true
$two == $three; // false
@jasny
Copy link
Author

jasny commented Oct 5, 2018

This supersedes #12. That ticket fails to properly identify and describe the problem.

@jasny
Copy link
Author

jasny commented Oct 5, 2018

Given #38, the ==, !=, >= and <= should also not be used if both parts are floats. This is already covered by that PR but could be covered by this test instead.

@jasny
Copy link
Author

jasny commented Oct 20, 2018

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

No branches or pull requests

1 participant