What is the difference between ==
and ===
?
- How exactly does the loosely
==
comparison work? - How exactly does the strict
===
comparison work?
What would be some useful examples?
What is the difference between ==
and ===
?
==
comparison work?===
comparison work? What would be some useful examples?
==
and ===
The difference between the loosely ==
equal operator and the strict ===
identical operator is exactly explained in the manual:
Comparison Operators
┌──────────┬───────────┬───────────────────────────────────────────────────────────┐ │ Example │ Name │ Result │ ├──────────┼───────────┼───────────────────────────────────────────────────────────┤ │$a == $b │ Equal │ TRUE if $a is equal to $b after type juggling. │ │$a === $b │ Identical │ TRUE if $a is equal to $b, and they are of the same type. │ └──────────┴───────────┴───────────────────────────────────────────────────────────┘
==
equal comparisonIf you are using the ==
operator, or any other comparison operator which uses loosely comparison such as !=
, <>
or ==
, you always have to look at the context to see what, where and why something gets converted to understand what is going on.
As reference and example you can see the comparison table in the manual:
Loose comparisons with
==
┌─────────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬─────────┬───────┬───────┐ │ │ TRUE │ FALSE │ 1 │ 0 │ -1 │ \"1\" │ \"0\" │ \"-1\" │ NULL │ array() │ \"php\" │ \"\" │ ├─────────┼───────┼───────┼───────┼───────┼───────┼───────┼───────┼───────┼───────┼─────────┼───────┼───────┤ │ TRUE │ TRUE │ FALSE │ TRUE │ FALSE │ TRUE │ TRUE │ FALSE │ TRUE │ FALSE │ FALSE │ TRUE │ FALSE │ │ FALSE │ FALSE │ TRUE │ FALSE │ TRUE │ FALSE │ FALSE │ TRUE │ FALSE │ TRUE │ TRUE │ FALSE │ TRUE │ │ 1 │ TRUE │ FALSE │ TRUE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ │ 0 │ FALSE │ TRUE │ FALSE │ TRUE │ FALSE │ FALSE │ TRUE │ FALSE │ TRUE │ FALSE │ TRUE │ TRUE │ │ -1 │ TRUE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ │ \"1\" │ TRUE │ FALSE │ TRUE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ │ \"0\" │ FALSE │ TRUE │ FALSE │ TRUE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ │ \"-1\" │ TRUE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ │ NULL │ FALSE │ TRUE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ TRUE │ FALSE │ TRUE │ │ array() │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ TRUE │ FALSE │ FALSE │ │ \"php\" │ TRUE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ │ \"\" │ FALSE │ TRUE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ TRUE │ └─────────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴─────────┴───────┴───────┘
===
identical comparisonIf you are using the ===
operator, or any other comparison operator which uses strict comparison such as !==
or ===
, then you can always be sure that the types won\'t magically change, because there will be no converting going on. So with strict comparison the type and value have to be the same, not only the value.
As reference and example you can see the comparison table in the manual:
Strict comparisons with
===
┌─────────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬─────────┬───────┬───────┐ │ │ TRUE │ FALSE │ 1 │ 0 │ -1 │ \"1\" │ \"0\" │ \"-1\" │ NULL │ array() │ \"php\" │ \"\" │ ├─────────┼───────┼───────┼───────┼───────┼───────┼───────┼───────┼───────┼───────┼─────────┼───────┼───────┤ │ TRUE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ │ 1 │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ │ 0 │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ │ -1 │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ │ \"1\" │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ │ \"0\" │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ │ \"-1\" │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ │ NULL │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ │ array() │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ │ \"php\" │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ │ \"\" │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ └─────────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴─────────┴───────┴───────┘
The operator == casts between two different types if they are different, while the === operator performs a \'typesafe comparison\'. That means that it will only return true if both operands have the same type and the same value.
Examples:
1 === 1: true
1 == 1: true
1 === \"1\": false // 1 is an integer, \"1\" is a string
1 == \"1\": true // \"1\" gets casted to an integer, which is 1
\"foo\" === \"foo\": true // both operands are strings and have the same value
Warning: two instances of the same class with equivalent members do NOT match the ===
operator. Example:
$a = new stdClass();
$a->foo = \"bar\";
$b = clone $a;
var_dump($a === $b); // bool(false)
A picture is worth a thousand words:
==
equality chart:===
Equality chart:Source code to create these images:
https://github.com/sentientmachine/php_equality_charts
Those who wish to keep their sanity, read no further.
PHP Variables that have not been declared yet are false.
False is equal to 0, blankstring and empty array and \"0\".
NAN does not == itself, but it is True.
A fresh class is == to 1.
If you are using PHP, Thou shalt not use the double equals operator, always use triple equals.
In regards to JavaScript:
The === operator works the same as the == operator, but it requires that its operands have not only the same value, but also the same data type.
For example, the sample below will display \'x and y are equal\', but not \'x and y are identical\'.
var x = 4;
var y = \'4\';
if (x == y) {
alert(\'x and y are equal\');
}
if (x === y) {
alert(\'x and y are identical\');
}
An addition to the other answers concerning object comparison:
== compares objects using the name of the object and their values. If two objects are of the same type and have the same member values, $a == $b
yields true.
=== compares the internal object id of the objects. Even if the members are equal, $a !== $b
if they are not exactly the same object.
class TestClassA {
public $a;
}
class TestClassB {
public $a;
}
$a1 = new TestClassA();
$a2 = new TestClassA();
$b = new TestClassB();
$a1->a = 10;
$a2->a = 10;
$b->a = 10;
$a1 == $a1;
$a1 == $a2; // Same members
$a1 != $b; // Different classes
$a1 === $a1;
$a1 !== $a2; // Not the same object
In simplest terms:
== checks if equivalent (value only)
=== checks if the same (value && type)
Equivalent vs. Same: An Analogy
1 + 1 = 2 + 0 (equivalent)
1 + 1 = 1 + 1 (same)
In PHP:
true == 1 (true - equivalent in value)
true === 1 (false - not the same in value && type)
It\'s all about data types. Take a BOOL
(true or false) for example:
true
also equals 1
and
false
also equals 0
The ==
does not care about the data types when comparing:
So if you had a variable that is 1 (which could also be true
):
$var=1;
And then compare with the ==
:
if ($var == true)
{
echo\"var is true\";
}
But $var
does not actually equal true
, does it? It has the int value of 1
instead, which in turn, is equal to true.
With ===
, the data types are checked to make sure the two variables/objects/whatever are using the same type.
So if I did
if ($var === true)
{
echo \"var is true\";
}
that condition would not be true, as $var !== true
it only == true
(if you know what I mean).
Why would you need this?
Simple - let\'s take a look at one of PHP\'s functions: array_search()
:
The array_search()
function simply searches for a value in an array, and returns the key of the element the value was found in. If the value could not be found in the array, it returns false. But, what if you did an array_search()
on a value that was stored in the first element of the array (which would have the array key of 0
)....the array_search()
function would return 0...which is equal to false..
So if you did:
$arr = array(\"name\");
if (array_search(\"name\", $arr) == false)
{
// This would return 0 (the key of the element the val was found
// in), but because we\'re using ==, we\'ll think the function
// actually returned false...when it didn\'t.
}
So, do you see how this could be an issue now?
Most people don\'t use == false
when checking if a function returns false. Instead, they use the !
. But actually, this is exactly the same as using ==false
, so if you did:
$arr = array(\"name\");
if (!array_search(\"name\", $arr)) // This is the same as doing (array_search(\"name\", $arr) == false)
So for things like that, you would use the ===
instead, so that the data type is checked.
One example is that a database attribute can be null or \"\":
$attributeFromArray = \"\";
if ($attributeFromArray == \"\"){} //true
if ($attributeFromArray === \"\"){} //true
if ($attributeFromArray == null){} //true
if ($attributeFromArray === null){} //false
$attributeFromArray = null;
if ($attributeFromArray == \"\"){} //true
if ($attributeFromArray === \"\"){} //false
if ($attributeFromArray == null){} //true
if ($attributeFromArray === null){} //true
Given x = 5
1) Operator : == is \"equal to\". x == 8
is false
2) Operator : === is \"exactly equal to\" (value and type) x === 5
is true, x === \"5\"
is false
Few of the examples
var_dump(5 == 5); // True
var_dump(5 == \"5\"); // True because == checks only same value not type
var_dump(5 === 5); // True
var_dump(5 === \"5\"); // False because value are same but data type are different.
P.S.
== Compares the value only, it won\'t bother about the data types
vs.
=== Compares the values and data types
$a = 5; // 5 as an integer
var_dump($a == 5); // compare value; return true
var_dump($a == \'5\'); // compare value (ignore type); return true
var_dump($a === 5); // compare type/value (integer vs. integer); return true
var_dump($a === \'5\'); // compare type/value (integer vs. string); return false
Be careful though. Here is a notorious problem.
// \'test\' is found at position 0, which is interpreted as the boolean \'false\'
if (strpos(\'testing\', \'test\')) {
// code...
}
vs.
// true, as strict comparison was made (0 !== false)
if (strpos(\'testing\', \'test\') !== false) {
// code...
}
In short, === works in the same manner that == does in most other programming languages.
PHP allows you to make comparisons that don\'t really make sense. Example:
$y = \"wauv\";
$x = false;
if ($x == $y)
...
While this allows for some interesting \"shortcuts\" you should beware since a function that returns something it shouldn\'t (like \"error\" instead of a number) will not get caught, and you will be left wondering what happened.
In PHP, == compares values and performs type conversion if necessary (for instance, the string \"12343sdfjskfjds\" will become \"12343\" in an integer comparison). === will compare the value AND type and will return false if the type is not the same.
If you look in the PHP manual, you will see that a lot of functions return \"false\" if the function fails, but they might return 0 in a successful scenario, which is why they recommend doing \"if (function() !== false)\" to avoid mistakes.
You would use === to test whether a function or variable is false rather than just equating to false (zero or an empty string).
$needle = \'a\';
$haystack = \'abc\';
$pos = strpos($haystack, $needle);
if ($pos === false) {
echo $needle . \' was not found in \' . $haystack;
} else {
echo $needle . \' was found in \' . $haystack . \' at location \' . $pos;
}
In this case strpos would return 0 which would equate to false in the test
if ($pos == false)
or
if (!$pos)
which is not what you want here.
As for when to use one over the other, take for example the fwrite()
function in PHP.
This function writes content to a file stream. According to PHP, \"fwrite()
returns the number of bytes written, or FALSE on error.\". If you want to test if the function call was successful, this method is flawed:
if (!fwrite(stuff))
{
log(\'error!\');
}
It can return zero (and is considered successful), and your condition still gets triggered. The right way would be:
if (fwrite(stuff) === FALSE)
{
log(\'error!\');
}
PHP is a loosely typed language. Using the double equal operator allows for a loose checking of a variable.
Loosely checking a value would allow for some similar, but not equal, values to equate as the same:
All of these values would equate as equal using the double equal operator.
Variables have a type and a value.
When you use these variables (in PHP), sometimes you don\'t have the good type. For example, if you do
if ($var == 1) {... do something ...}
PHP have to convert (\"to cast\") $var to integer. In this case, \"$var == 1\" is true because any non-empty string is casted to 1.
When using ===, you check that the value AND THE TYPE are equal, so \"$var === 1\" is false.
This is useful, for example, when you have a function that can return false (on error) and 0 (result) :
if(myFunction() == false) { ... error on myFunction ... }
This code is wrong as if myFunction()
returns 0, it is casted to false and you seem to have an error. The correct code is :
if(myFunction() === false) { ... error on myFunction ... }
because the test is that the return value \"is a boolean and is false\" and not \"can be casted to false\".
The ===
operator is supposed to compare exact content equality while the ==
operator would compare semantic equality. In particular it will coerce strings to numbers.
Equality is a vast subject. See the Wikipedia article on equality.
<?php
/**
* Comparison of two PHP objects == ===
* Checks for
* 1. References yes yes
* 2. Instances with matching attributes and its values yes no
* 3. Instances with different attributes yes no
**/
// There is no need to worry about comparing visibility of property or
// method, because it will be the same whenever an object instance is
// created, however visibility of an object can be modified during run
// time using ReflectionClass()
// http://php.net/manual/en/reflectionproperty.setaccessible.php
//
class Foo
{
public $foobar = 1;
public function createNewProperty($name, $value)
{
$this->{$name} = $value;
}
}
class Bar
{
}
// 1. Object handles or references
// Is an object a reference to itself or a clone or totally a different object?
//
// == true Name of two objects are same, for example, Foo() and Foo()
// == false Name of two objects are different, for example, Foo() and Bar()
// === true ID of two objects are same, for example, 1 and 1
// === false ID of two objects are different, for example, 1 and 2
echo \"1. Object handles or references (both == and ===) <br />\";
$bar = new Foo(); // New object Foo() created
$bar2 = new Foo(); // New object Foo() created
$baz = clone $bar; // Object Foo() cloned
$qux = $bar; // Object Foo() referenced
$norf = new Bar(); // New object Bar() created
echo \"bar\";
var_dump($bar);
echo \"baz\";
var_dump($baz);
echo \"qux\";
var_dump($qux);
echo \"bar2\";
var_dump($bar2);
echo \"norf\";
var_dump($norf);
// Clone: == true and === false
echo \'$bar == $bar2\';
var_dump($bar == $bar2); // true
echo \'$bar === $bar2\';
var_dump($bar === $bar2); // false
echo \'$bar == $baz\';
var_dump($bar == $baz); // true
echo \'$bar === $baz\';
var_dump($bar === $baz); // false
// Object reference: == true and === true
echo \'$bar == $qux\';
var_dump($bar == $qux); // true
echo \'$bar === $qux\';
var_dump($bar === $qux); // true
// Two different objects: == false and === false
echo \'$bar == $norf\';
var_dump($bar == $norf); // false
echo \'$bar === $norf\';
var_dump($bar === $norf); // false
// 2. Instances with matching attributes and its values (only ==).
// What happens when objects (even in cloned object) have same
// attributes but varying values?
// $foobar value is different
echo \"2. Instances with matching attributes and its values (only ==) <br />\";
$baz->foobar = 2;
echo \'$foobar\' . \" value is different <br />\";
echo \'$bar->foobar = \' . $bar->foobar . \"<br />\";
echo \'$baz->foobar = \' . $baz->foobar . \"<br />\";
echo \'$bar == $baz\';
var_dump($bar == $baz); // false
// $foobar\'s value is the same again
$baz->foobar = 1;
echo \'$foobar\' . \" value is the same again <br />\";
echo \'$bar->foobar is \' . $bar->foobar . \"<br />\";
echo \'$baz->foobar is \' . $baz->foobar . \"<br />\";
echo \'$bar == $baz\';
var_dump($bar == $baz); // true
// Changing values of properties in $qux object will change the property
// value of $bar and evaluates true always, because $qux = &$bar.
$qux->foobar = 2;
echo \'$foobar value of both $qux and $bar is 2, because $qux = &$bar\' . \"<br />\";
echo \'$qux->foobar is \' . $qux->foobar . \"<br />\";
echo \'$bar->foobar is \' . $bar->foobar . \"<br />\";
echo \'$bar == $qux\';
var_dump($bar == $qux); // true
// 3. Instances with different attributes (only ==)
// What happens when objects have different attributes even though
// one of the attributes has same value?
echo \"3. Instances with different attributes (only ==) <br />\";
// Dynamically create a property with the name in $name and value
// in $value for baz object
$name = \'newproperty\';
$value = null;
$baz->createNewProperty($name, $value);
echo \'$baz->newproperty is \' . $baz->{$name};
var_dump($baz);
$baz->foobar = 2;
echo \'$foobar\' . \" value is same again <br />\";
echo \'$bar->foobar is \' . $bar->foobar . \"<br />\";
echo \'$baz->foobar is \' . $baz->foobar . \"<br />\";
echo \'$bar == $baz\';
var_dump($bar == $baz); // false
var_dump($bar);
var_dump($baz);
?>
All of the answers so far ignore a dangerous problem with ===. It has been noted in passing, but not stressed, that integer and double are different types, so the following code:
$n = 1000;
$d = $n + 0.0e0;
echo \'<br/>\'. ( ($n == $d)?\'equal\' :\'not equal\' );
echo \'<br/>\'. ( ($n === $d)?\'equal\' :\'not equal\' );
gives:
equal
not equal
Note that this is NOT a case of a \"rounding error\". The two numbers are exactly equal down to the last bit, but they have different types.
This is a nasty problem because a program using === can run happily for years if all of the numbers are small enough (where \"small enough\" depends on the hardware and OS you are running on). However, if by chance, an integer happens to be large enough to be converted to a double, its type is changed \"forever\" even though a subsequent operation, or many operations, might bring it back to a small integer in value. And, it gets worse. It can spread - double-ness infection can be passed along to anything it touches, one calculation at a time.
In the real world, this is likely to be a problem in programs that handle dates beyond the year 2038, for example. At this time, UNIX timestamps (number of seconds since 1970-01-01 00:00:00 UTC) will require more than 32-bits, so their representation will \"magically\" switch to double on some systems. Therefore, if you calculate the difference between two times you might end up with a couple of seconds, but as a double, rather than the integer result that occurs in the year 2017.
I think this is much worse than conversions between strings and numbers because it is subtle. I find it easy to keep track of what is a string and what is a number, but keeping track of the number of bits in a number is beyond me.
So, in the above answers there are some nice tables, but no distinction between 1 (as an integer) and 1 (subtle double) and 1.0 (obvious double). Also, advice that you should always use === and never == is not great because === will sometimes fail where == works properly. Also, JavaScript is not equivalent in this regard because it has only one number type (internally it may have different bit-wise representations, but it does not cause problems for ===).
My advice - use neither. You need to write your own comparison function to really fix this mess.
There are two differences between ==
and ===
in PHP arrays and objects that I think didn\'t mention here; two arrays with different key sorts, and objects.
If you have an array with a key sort and another array with a different key sort, they are strictly different (i.e. using ===
). That may cause if you key-sort an array, and try to compare the sorted array with the original one.
For instance, consider an empty array. First, we try to push some new indexes to the array without any special sort. A good example would be an array with strings as keys. Now deep into an example:
// Define an array
$arr = [];
// Adding unsorted keys
$arr[\"I\"] = \"we\";
$arr[\"you\"] = \"you\";
$arr[\"he\"] = \"they\";
Now, we have a not-sorted-keys array (e.g., \'he\' came after \'you\'). Consider the same array, but we sorted its keys alphabetically:
// Declare array
$alphabetArr = [];
// Adding alphabetical-sorted keys
$alphabetArr[\"I\"] = \"we\";
$alphabetArr[\"he\"] = \"they\";
$alphabetArr[\"you\"] = \"you\";
Tip: You can sort an array by key using ksort() function.
Now you have another array with a different key sort from the first one. So, we\'re going to compare them:
$arr == $alphabetArr; // true
$arr === $alphabetArr; // false
Note: It may be obvious, but comparing two different arrays using strict comparison always results false
. However, two arbitrary arrays may be equal using ===
or not.
You would say: \"This difference is negligible\". Then I say it\'s a difference and should be considered and may happen anytime. As mentioned above, sorting keys in an array is a good example of that.
Keep in mind, two different objects are never strict-equal. These examples would help:
$stdClass1 = new stdClass();
$stdClass2 = new stdClass();
$clonedStdClass1 = clone $stdClass1;
// Comparing
$stdClass1 == $stdClass2; // true
$stdClass1 === $stdClass2; // false
$stdClass1 == $clonedStdClass1; // true
$stdClass1 === $clonedStdClass1; // false
Note: Assigning an object to another variable does not create a copy - rather, it creates a reference to the same memory location as the object. See here.
Note: As of PHP7, anonymous classes was added. From the results, there is no difference between new class {}
and new stdClass()
in the tests above.