PHP Gotcha #4: Equality

Today’s gotcha brought to you by the PHP sadness website, specifically this article

The example from the beginning of that article should prove illustrative of the problem.


$ php -r 'var_dump(TRUE == "a"); var_dump("a" == 0); var_dump(TRUE == 0);'
bool(true)
bool(true)
bool(false)

$ php -r 'var_dump(-INF < 0); var_dump(0 < TRUE); var_dump(-INF < TRUE);'
bool(true)
bool(true)
bool(false)

Let’s face it, the loose comparison operator ( == ) is wonky. I could go on for a couple more paragraphs as to how wonky, but it’s been said before and the article linked above does a better job than I could anyway. As has been said many times in many threads here, don’t use ==. Use === instead.

Very helpful thread, thanks for posting this Michael Morris. I used to run into a weird bug on my website with “==”, it gave me errors like ‘nesting too deep’. Clearly the ‘==’ sign wasnt doing the job and the code aint breaking out of loop. I changed it to ‘===’ and everything worked like a charm. Id recommend to use “===”, at least for object comparison.

If I recall == checks for equal values while === checks for equal values and equal types.

In python I guess this would be written as “type(x) == type(y) and x==y”. It might be more typing but I prefer clarity over unusual syntax.

Sent from my XT316 using Tapatalk 2

For scalars, yes. For objects, no.

Two objects are deemed equal under == when they are instances of the same class and all their attributes have the same values, whereas they are the same under === when the variables point to the same instance.

Thus:


class foo
{
    private $a;
    public function __construct($a)
    {
        $this->a = $a;
    }
}

$bar = new foo(1);
$baz = new foo(1);

var_dump($bar == $baz); // true
var_dump($bar === $baz); // false
var_dump($bar === $bar); // true

The problem is PHP itself, it is loosely typed, if it was a strictly typed language this wouldn’t be an issue.

You can work around this issue by writing classes that represent data types, for instance:
$bar = FALSE;
$foo = new String(‘this is a string’);
$foo->compare($bar); // would return FALSE because the two variables are of a different type

Code smells lead to the issues mentioned, just because PHP provides the ability to type juggle, it doesn’t mean you should use this feature.

In all honesty I don’t see merit in this solution, since you still need to use either == or ===, except now you’ve moved it to a class method, instead of displaying it directly.
So if I want to know whether you’ve used == or ===, I’d have to check the code in your classes, whereas if you’d used == or === I could see it directly.
Even worse, you could have implemented as


class String
{
    private $str;
    public function __construct($str)
    {
        $this->str = $str;
    }
    public function compare($that)
    {
        return $this === $that;
    }
}

so that


$foo = new String("foo");
$bar = new String("foo");

var_dump($foo->compare($bar)); // false

:eek2:

I agree that wrapping it in a class method doesn’t do a lot to overcome the idiosyncrasies of PHP equality checking.

What will be interesting is how Discourse style upvoting and downvoting will affect controversial questions like these. Especially when the total number of voters is no where near the sample pool of voters you get on StackExchange and the statistical margin of error is a lot higher.

Sent from my XT316 using Tapatalk 2

Off Topic:

it sure will be interesting to see, but we won’t have downvoting, we’ll only have upvoting (called “like”)