How do the PHP equality (== double equals) and identity (=== triple equals) comparison operators differ?
- 松散的
== 比较究竟是如何工作的? - 严格的
=== 比较究竟是如何工作的?
有哪些有用的例子?
本手册对松散
Comparison Operators
1
2
3
4
5
6 ┌──────────┬───────────┬───────────────────────────────────────────────────────────┐
│ 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. │
└──────────┴───────────┴───────────────────────────────────────────────────────────┘
不严格地说,
如果您使用的是
- 转换为布尔值
- 转换为整数
- 转换为浮动
- 转换为字符串
- 转换为数组
- 转换为对象
- 转换为资源
- 转换为空
类型比较表
作为参考和示例,您可以在手册中看到比较表:
Loose comparisons with
==
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 ┌─────────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬─────────┬───────┬───────┐
│ │ 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 │
└─────────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴─────────┴───────┴───────┘
严格的
如果您使用的是
作为参考和示例,您可以在手册中看到比较表:
Strict comparisons with
===
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 ┌─────────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬─────────┬───────┬───────┐
│ │ 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 │
└─────────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴─────────┴───────┴───────┘
如果两个不同类型之间的类型不同,则运算符==强制转换,而==运算符执行"类型安全比较"。这意味着只有当两个操作数具有相同的类型和值时,它才会返回true。
实例:
1 2 3 4 5 | 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 |
警告:具有等效成员的同一类的两个实例与
1 2 3 4 |
一幅画胜过千言万语:
php double等于创建这些图像的源代码:
https://github.com/sentinentmachine/php_equality_图表
大师冥想那些希望保持清醒的人,不要再读下去,因为这些都没有任何意义,除了说这就是PHP疯狂分形的设计。
引号中的十六进制字符串偶尔是一个浮点数,它将被意外地强制转换为违背您的意愿的浮点数,从而导致运行时错误。
当数字足够大时,它们就等于无穷大。
一个新的类是==到1。
希望:
如果使用php,则不应使用double equals运算符,因为如果使用triple equals,则唯一需要担心的边缘情况是NaN和接近无穷大的数字,它们被强制转换为无穷大。有了双等号,任何事物都会对任何事物或事物感到惊讶,或是对你的意愿和你的意愿感到惊讶,而这两者显然是相等的。
在PHP中使用
关于javascript:
===运算符的工作方式与==运算符相同,但它要求其操作数不仅具有相同的值,而且具有相同的数据类型。
例如,下面的示例将显示"x和y相等",但不显示"x和y相同"。
1 2 3 4 5 6 7 8 | var x = 4; var y = '4'; if (x == y) { alert('x and y are equal'); } if (x === y) { alert('x and y are identical'); } |
关于对象比较的其他答案的补充:
==使用对象名称及其值比较对象。如果两个对象的类型相同且成员值相同,则
===比较对象的内部对象ID。即使成员是平等的,如果他们不是完全相同的对象,则为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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 |
简单来说:
==检查是否等效(仅限值)
==检查是否相同(值和类型)
等效与相同:类比
1+1=2+0(等效)
1+1=1+1(相同)
在PHP中:
真==1(真-等值)
true==1(false-值和类型不相同)
- 布尔是真的
- 1是int
这都是关于数据类型的。以
在比较时,
然后与
1 2 3 4 | if ($var == true) { echo"var is true"; } |
但
使用
如果我做到了
1 2 3 4 | if ($var === true) { echo"var is true"; } |
这种情况不会是真的,因为
你为什么需要这个?
简单-让我们来看一看PHP的一个函数:
如果你这样做:
1 2 3 4 5 6 7 | $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. } |
那么,你知道这现在怎么会成为一个问题吗?
大多数人在检查函数是否返回false时不使用
1 2 | $arr = array("name"); if (!array_search("name", $arr)) // This is the same as doing (array_search("name", $arr) == false) |
因此,对于这种情况,您将使用
例如,数据库属性可以为空或":
1 2 3 4 5 6 7 8 9 10 11 | $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 |
以
1)运算符:==为"等于"。
很少有这样的例子
1 2 3 4 |
附笔。
== Compares the value only, it won't bother about the data types
VS
=== Compares the values and data types
简而言之,==
PHP允许您进行真正意义不大的比较。例子:
1 2 3 4 | $y ="wauv"; $x = false; if ($x == $y) ... |
虽然这允许一些有趣的"快捷方式",但您应该注意,因为返回不应该返回的内容的函数(如"错误"而不是数字)不会被捕获,您将不知道发生了什么。
在php中,==比较值并在必要时执行类型转换(例如,在整数比较中,字符串"12343sdfjskfjds"将变为"12343")。==将比较值和类型,如果类型不同,则返回false。
如果您在PHP手册中看到,如果函数失败,很多函数都会返回"false",但在成功的情况下,它们可能会返回0,这就是为什么它们建议执行"if(function()!==false)"以避免错误。
1 2 3 4 5 6 |
不过要小心。这是一个众所周知的问题。
1 2 3 4 | // 'test' is found at position 0, which is interpreted as the boolean 'false' if (strpos('testing', 'test')) { // code... } |
VS
1 2 3 4 | // true, as strict comparison was made (0 !== false) if (strpos('testing', 'test') !== false) { // code... } |
php==是比较变量值的比较运算符。但是==比较值和数据类型。
例如,
1 2 3 4 5 6 7 8 9 10 | <?php $var1 = 10; $var2 = '10'; if($var1 == $var2) { echo 'Variables are equal'; } else { echo 'Variables are not equal'; } ?> |
在这种情况下,输出将是"变量相等",即使它们的数据类型不同。
但是如果我们使用==而不是==,输出将是"变量不相等"。PHP首先比较变量的值,然后比较数据类型。这里的值相同,但数据类型不同。
PHP是一种松散类型的语言。使用double equal运算符可以对变量进行松散检查。
松散地检查一个值将允许一些类似但不相等的值等同于相同的值:
- ’
- 无效的
- 假
- 零
使用双等号运算符,所有这些值都将等于相等。
至于何时使用其中一个,以PHP中的
此函数将内容写入文件流。根据php,"
它可以返回零(并且被认为是成功的),并且您的条件仍然会被触发。正确的方法是:
您将使用==来测试函数或变量是否为假,而不仅仅是等于假(零或空字符串)。
1 2 3 4 5 6 7 8 | $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; } |
在这种情况下,strpos将返回0,这在测试中等同于false。
1 | if ($pos == false) |
或
1 | if (!$pos) |
这不是你想要的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | <?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); ?> |
平等是一个广泛的主题。参见维基百科关于平等的文章。
到目前为止,所有的答案都忽略了一个危险的问题,即==。在传递中注意到整数和double是不同的类型,但不强调,因此下面的代码是:
1 2 3 4 | $n = 1000; $d = $n + 0.0e0; echo '<br/>'. ( ($n == $d)?'equal' :'not equal' ); echo '<br/>'. ( ($n === $d)?'equal' :'not equal' ); |
给予:
1 2 | equal not equal |
注意,这不是"舍入误差"的情况。这两个数字与最后一位完全相等,但它们的类型不同。
这是一个棘手的问题,因为如果所有的数字都足够小(其中"足够小"取决于运行的硬件和操作系统),使用==的程序可以运行数年。但是,如果一个整数恰好足够大,可以转换为double,则它的类型将"永久"更改,即使后续操作或许多操作可能会使其返回到一个小的值整数。而且,情况更糟。它可以传播-双尼斯感染可以通过它接触到的任何东西,一次一个计算。
在现实世界中,这在处理2038年之后日期的程序中可能是一个问题。此时,Unix时间戳(1970-01-01 00:00:00 UTC以来的秒数)将需要32位以上,因此在某些系统上,它们的表示将"神奇地"切换到双倍。因此,如果你计算两次之间的差额,你可能会得到几秒钟的时间,但结果是双倍的,而不是2017年的整数结果。
我认为这比字符串和数字之间的转换更糟糕,因为它很微妙。我发现跟踪什么是字符串,什么是数字很容易,但是跟踪数字中的位数是我无法理解的。
所以,在上面的答案中有一些很好的表格,但是1(作为整数)和1(微妙的双精度)和1.0(明显的双精度)之间没有区别。另外,应该始终使用==和never==的建议并不好,因为==有时会在==正常工作时失败。另外,javascript在这方面也不是等价的,因为它只有一个数字类型(在内部它可能有不同的位表示,但它不会导致==的问题)。
我的建议-两者都不要用。您需要编写自己的比较函数来真正修复这一混乱局面。
变量有一个类型和一个值。
- $var="test"是包含"test"的字符串
- $var2=24是一个整数,vhose值为24。
当您使用这些变量(在PHP中)时,有时您没有好的类型。例如,如果你这样做
1 | if ($var == 1) {... do something ...} |
PHP必须将("to cast")$var转换为整数。在这种情况下,"$var==1"为真,因为任何非空字符串都被强制转换为1。
使用==时,检查值和类型是否相等,因此"$var==1"为假。
这很有用,例如,当您有一个函数可以返回false(出错时)和0(结果时):
1 | if(myFunction() == false) { ... error on myFunction ... } |
这段代码是错误的,好像
1 | if(myFunction() === false) { ... error on myFunction ... } |
因为测试是返回值"是一个布尔值且为假",而不是"可以强制转换为假"。
在PHP数组和对象中,
如果您有一个具有键排序的数组和另一个具有不同键排序的数组,那么它们是完全不同的(即使用
例如,考虑一个空数组。首先,我们尝试在不进行任何特殊排序的情况下将一些新索引推送到数组中。一个很好的例子是使用字符串作为键的数组。现在深入到一个例子中:
1 2 3 4 5 6 7 | // Define an array $arr = []; // Adding unsorted keys $arr["I"] ="we"; $arr["you"] ="you"; $arr["he"] ="they"; |
现在,我们有一个未排序的键数组(例如,"he"在"you"后面)。考虑相同的数组,但我们按字母顺序对其键进行排序:
1 2 3 4 5 6 7 | // Declare array $alphabetArr = []; // Adding alphabetical-sorted keys $alphabetArr["I"] ="we"; $alphabetArr["he"] ="they"; $alphabetArr["you"] ="you"; |
提示:可以使用ksort()函数按键对数组进行排序。
现在,您有了另一个与第一个数组具有不同键排序的数组。因此,我们将对它们进行比较:
1 2 | $arr == $alphabetArr; // true $arr === $alphabetArr; // false |
注意:这可能很明显,但是使用严格比较比较两个不同的数组总是会得到
你会说:"这种差异是可以忽略的。"然后我说这是一个区别,应该考虑,而且可能随时发生。如上所述,对数组中的键进行排序就是一个很好的例子。
物体记住,两个不同的对象永远不会严格相等。这些例子将有助于:
1 2 3 4 5 6 7 8 9 | $stdClass1 = new stdClass(); $stdClass2 = new stdClass(); $clonedStdClass1 = clone $stdClass1; // Comparing $stdClass1 == $stdClass2; // true $stdClass1 === $stdClass2; // false $stdClass1 == $clonedStdClass1; // true $stdClass1 === $clonedStdClass1; // false |
注意:将一个对象分配给另一个变量并不会创建一个副本,而是创建一个对与该对象相同内存位置的引用。请看这里。
注意:从php7开始,添加了匿名类。从结果来看,在上述试验中,