PHP 相等(== double equals)和恒等式(=== triple equals)比较运算符有何不同?

How do the PHP equality (== double equals) and identity (=== triple equals) comparison operators differ?

提问人:nickf 提问时间:9/17/2008 最后编辑:Muhammad Dyas Yaskurnickf 更新时间:8/29/2023 访问量:381336

问:

和 和有什么不一样?=====

  • 松散比较究竟是如何工作的?==
  • 严格比较究竟是如何工作的?===

有哪些有用的例子?

PHP 运算符

评论

0赞 klutt 2/15/2021
@BenAubin 说真的,你所做的编辑根本没有改善任何东西。
0赞 klutt 2/15/2021
@BenAubin 我知道你想帮忙,这很好,但这些编辑真的没有改善东西。现在,当您拥有足够多的代表时,您的编辑将不会进入审核队列,因此请小心您的编辑。
0赞 Ben Aubin 3/4/2021
@klutt 我的编辑是故意的。OP 在原始帖子的几分钟内进行了编辑,要求同时使用 Javascript 和 PHP,因此许多答案都引用了这两种语言。正如我在编辑注释中提到的,我的编辑带回了这个原始上下文。

答:

706赞 nickf 9/17/2008 #1

和 之间的区别=====

松散相等的运算符和严格相同的运算符之间的区别在手册中得到了确切的解释:=====

比较运算符

名字 结果
$a == $b 平等 如果 $a 等于 $b,则为 TRUE。
$a === $b 相同 如果 $a 等于 $b,并且它们属于同一类型,则为 TRUE。

大致相等的比较==

如果您使用的是运算符,或任何其他使用松散比较的比较运算符,例如 或 ,则始终必须查看上下文以查看转换的内容、位置和原因,以了解发生了什么。==!=<>==

转换规则

类型比较表

作为参考和示例,您可以在手册中看到比较表:

1 0 -1 "1" "0" "-1" 数组() “php” ""
1
0
-1
"1"
"0"
"-1"
数组()
“php”
""

严格相同的比较===

如果您使用的是运算符,或者使用严格比较的任何其他比较运算符,例如 ,那么您始终可以确定类型不会神奇地更改,因为不会进行转换。因此,通过严格的比较,类型和价值必须相同,而不仅仅是价值。===!=====

类型比较表

作为参考和示例,您可以在手册中看到比较表:

===

1 0 -1 "1" "0" "-1" 数组() “php” ""
1
0
-1
"1"
"0"
"-1"
数组()
“php”
""

编者注 - 这在之前被正确引用,但作为 Markdown 表格更具可读性。这不是抄袭

评论

73赞 nickf 9/17/2008
还有人觉得“000”==“0000”很奇怪吗?
39赞 Pim Jager 8/17/2009
总是让我感到惊讶的是 false == array(),false == 0 但 array() != 0,所以 false == array() !=/== 0?这对我来说很奇怪。
4赞 deceze 8/17/2009
@Pim......继续:这样看:转换为布尔值,任何值只需要落在两边之一,或者。这很容易投射。然而,出于所有实际目的,所有其他值都具有几乎无限的组合。是????truefalse"five" == 5array(0) == 0array(0,0,0) == 00.0000000000000000000000000000000000000000000000000001 == array()
13赞 Pacerier 8/2/2013
@Raithlin,小心阵列。triple equals 在 javascript 中给出了不同的数组,但对于 PHP 来说,只要它们的值相等falsetrue
14赞 Pacerier 8/8/2013
@Raithlin,还有很多很多的陷阱。在 JavaScript 中:、、、、、、、、。在 PHP 中,它是相反的行为:、、、、。"000" != "00""000" == null"000" == false"0x0" == falsearray() == 0false != nullarray() != nullfalse == "0x0"false == "000""000" == "00""000" != null"000" != false"0x0" != falsearray() != 0false == nullarray() == nullfalse != "0x0"false != "000"
2赞 Stacey Richards 9/17/2008 #2

您可以使用 === 来测试函数或变量是否为 false,而不仅仅是等同于 false(零或空字符串)。

$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

if ($pos == false)

if (!$pos)

这不是你在这里想要的。

31赞 user1684 9/17/2008 #3

关于 JavaScript:

=== 运算符的工作方式与 == 运算符相同,但它要求其操作数不仅具有相同的值,而且具有相同的数据类型。

例如,下面的示例将显示“x 和 y 相等”,但不显示“x 和 y 相同”。

var x = 4;
var y = '4';
if (x == y) {
    alert('x and y are equal');
}
if (x === y) {
    alert('x and y are identical');
}

评论

1赞 xdazz 5/4/2013
@DavidThomas 这并不完全相同。看到 stackoverflow.com/questions/12598407/...
1赞 mickmackusa 9/1/2020
我之所以对这个答案进行 DV 处理,是因为它是在 OP 的自我回答详细说明了关于松散类型比较的相同见解后 30 分钟出现的。这个 javascript 对最初和当前带有 php 标签的问题的回答确实应该被删除,但要做到这一点,投票统计需要通过社区的努力来降低。换句话说,需要更多的 DV 才能进行适当的管理并删除此(已删除用户的)答案。
1赞 ofaurax 9/17/2008 #4

变量具有类型和值。

  • $var = “test” 是包含 “test” 的字符串
  • $var 2 = 24 是一个整数,vhose 值为 24。

当你使用这些变量(在PHP中)时,有时你没有好的类型。 例如,如果您这样做

if ($var == 1) {... do something ...}

PHP 必须将 (“to cast”) $var转换为整数。在本例中,“$var == 1”为 true,因为任何非空字符串都转换为 1。

使用 === 时,检查值 AND THE TYPE 是否相等,因此 “$var === 1” 为 false。

这很有用,例如,当您有一个可以返回 false(错误)和 0(结果)的函数时:

if(myFunction() == false) { ... error on myFunction ... }

此代码是错误的,好像返回 0,它被强制转换为 false,您似乎有错误。正确的代码是:myFunction()

if(myFunction() === false) { ... error on myFunction ... }

因为测试是返回值“是布尔值并且是假的”而不是“可以强制转换为假的”。

评论

0赞 nickf 9/17/2008
关于非空字符串,这实际上不是真的。“a” == 0 为 TRUE。
252赞 Patrick Glandien 2/26/2009 #5

如果两个不同的类型不同,则运算符 == 在它们之间转换,而 === 运算符执行“类型安全比较”。这意味着只有当两个操作数具有相同的类型和相同的值时,它才会返回 true。

例子:

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

警告:具有等效成员的同一类的两个实例与运算符不匹配。例:===

$a = new stdClass();
$a->foo = "bar";
$b = clone $a;
var_dump($a === $b); // bool(false)

评论

3赞 gnud 2/26/2009
吹毛求疵:=== 仅在两个操作数类型相同且值相等时返回 true =)
1赞 Rob Stevenson-Leggett 2/26/2009
@gnud 这正是他在示例中显示的内容。如果只是比较类型,那就被称为“类型比较”,不是吗?
3赞 4/13/2009
在使用 PHP 8 年之后,昨天是我第一次陷入我应该使用 === 的情况
4赞 Jeremy C 10/23/2012
=== 如果它们相等且类型相同,则为 true。== 如果它们相等,则为 true。如果它们不相等,则为 true。!== 如果它们不相等,或者相等但类型不相同,则为 true。
1赞 clauziere 3/19/2014
此外,使用 === 比 == 稍快,因为它不需要在检查值是否相等之前转换值。
23赞 soulmerge 2/26/2009 #6

对有关对象比较的其他答案的补充:

== 使用对象的名称及其值比较对象。如果两个对象属于同一类型且具有相同的成员值,则结果为 true。$a == $b

=== 比较对象的内部对象 ID。即使成员相等,如果它们不完全相同。$a !== $b

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
9赞 user849137 7/19/2012 #7

这一切都与数据类型有关。以 (true 或 false) 为例:BOOL

true也等于,也等于1false0

比较时不关心数据类型: 因此,如果您有一个变量是 1(也可以是):==true

$var=1;

然后与:==

if ($var == true)
{
    echo"var is true";
}

但实际上并不等于,是吗?它的 int 值为 instead,而 instead 又等于 true。$vartrue1

使用 ,检查数据类型以确保两个变量/对象/任何东西使用相同的类型。===

所以如果我这样做了

if ($var === true)
{
    echo "var is true";
}

那个条件是不正确的,因为它只是(如果你明白我的意思)。$var !== true== true

你为什么需要这个?

简单 - 让我们来看看PHP的一个功能:array_search()

该函数只是在数组中搜索值,并返回找到该值的元素的键。如果在数组中找不到该值,则返回 false。但是,如果你对存储在数组的第一个元素中的值(该数组键为 )执行了什么操作......该函数将返回 0...,这等于 false。.array_search()array_search()0array_search()

因此,如果您这样做了:

$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 时不会使用。相反,他们使用 .但实际上,这与使用 完全相同,所以如果你这样做了:== false!==false

$arr = array("name");
if (!array_search("name", $arr)) // This is the same as doing (array_search("name", $arr) == false)

因此,对于类似的事情,您可以改用 ,以便检查数据类型。===

1赞 Sathish 9/18/2015 #8
<?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);
?>
121赞 Eric Leschinski 11/3/2016 #9

一张图片胜过千言万语:

PHP Double Equals 相等图表:==

enter image description here

PHP 三重等于相等图表:===

enter image description here

用于创建这些映像的源代码:

https://github.com/sentientmachine/php_equality_charts

大师禅修

那些希望保持理智的人,不要再读下去了,因为这些都没有任何意义,只能说这就是PHP的疯狂分形的设计方式。

  1. NAN != NAN但。NAN == true

  2. ==如果 left 是数字,则将左操作数和右操作数转换为数字。所以,但是123 == "123foo""123" != "123foo"

  3. 引号中的十六进制字符串有时是浮点数,并且会出人意料地违背您的意愿浮点数,从而导致运行时错误。

  4. ==不是传递的,因为 和 但是"0"== 00 == """0" != ""

  5. 尚未声明的 PHP 变量是 false,即使 PHP 有一种方法来表示未定义的变量,该功能也会被禁用。==

  6. "6" == " 6"、 和 但是 。但是,在未经您的指示或同意的情况下,将意外的字符串转换为八进制将发生,从而导致运行时错误。"4.2" == "4.20""133" == "0133"133 != 0133"0x10" == "16""1e3" == "1000"

  7. False == 0和。""[]"0"

  8. 如果将 1 加到数字上,并且它们已经保持其最大值,则它们不会换行,而是被强制转换为 。infinity

  9. 一个新类是 == 到 1。

  10. False 是最危险的值,因为 False 对大多数其他变量来说都是 ==,主要是违背了它的目的。

希望:

如果您使用的是 PHP,则不应使用双等于运算符,因为如果您使用三等于,唯一需要担心的边缘情况是 NAN 和数字非常接近其数据类型的最大值,以至于它们被强制转换为无穷大。有了双重相等,任何事情都可以对任何事物感到惊讶,或者可以对违背你的意愿感到惊讶,并且对它显然应该相等的东西感到惊讶。==!=

你在PHP中使用的任何地方都有一种难闻的代码气味,因为其中有85个错误暴露在隐式强制转换规则中,这些规则似乎是由数百万程序员通过布朗运动编程设计的。==

评论

1赞 Chazy Chaz 1/17/2017
始终使用三等于真的是一个好主意(也是安全的)吗?
3赞 Eric Leschinski 1/17/2017
是的,三重等于的传递属性使其更安全和网络规模。
1赞 Tim 1/16/2020
一个数字怎么可能接近无穷大?[爆炸大脑动图]
2赞 Jake 11/14/2020
值得注意的是,这可能有点麻烦,例如1.0 !== 1floor(4 / 3) === 1 ? 'works as might be expected' : 'what?'
1赞 Jake 11/15/2020
@EricLeschinski 的计算结果不为 true,因为 floor 返回 a(即使返回值一定是整数,它不是按类型计算的)——因此需要指出这个问题。JavaScript 没有这个问题,因为只有一种数值类型(尽管还有其他问题,例如整数舍入)。floor(4/3) === 1float
2赞 DavidWalley 5/9/2017 #10

到目前为止,所有答案都忽略了 === 的危险问题。顺便说一句,整数和双精度是不同的类型,所以下面的代码是:

$n = 1000;
$d = $n + 0.0e0;
echo '<br/>'. ( ($n ==  $d)?'equal' :'not equal' );
echo '<br/>'. ( ($n === $d)?'equal' :'not equal' );

给:

 equal
 not equal

请注意,这不是“舍入错误”的情况。这两个数字在最后一位完全相等,但它们具有不同的类型。

这是一个令人讨厌的问题,因为如果所有数字都足够小,使用 === 的程序可以愉快地运行多年(其中“足够小”取决于您运行的硬件和操作系统)。但是,如果碰巧一个整数恰好大到足以转换为双精度值,则其类型将“永远”更改,即使后续操作或许多操作可能会将其值恢复为小整数。而且,情况变得更糟。它可以传播 - 双重感染可以传递给它所接触的任何东西,一次一个计算。

例如,在现实世界中,这在处理 2038 年以后日期的程序中可能是一个问题。此时,UNIX 时间戳(自 1970-01-01 00:00:00 UTC 以来的秒数)将需要超过 32 位,因此它们表示将在某些系统上“神奇地”切换为双倍。因此,如果您计算两次之间的差异,您最终可能会得到几秒钟,但作为双倍,而不是 2017 年发生的整数结果。

我认为这比字符串和数字之间的转换要糟糕得多,因为它很微妙。我发现跟踪什么是字符串,什么是数字很容易,但跟踪数字中的位数超出了我的范围。

因此,在上面的答案中,有一些不错的表格,但 1(作为整数)和 1(微妙的双精度)和 1.0(明显的双精度)之间没有区别。此外,您应该始终使用 === 而不是 == 的建议不是很好,因为 === 有时会在 == 正常工作的情况下失败。此外,JavaScript 在这方面并不等价,因为它只有一种数字类型(在内部它可能具有不同的按位表示,但它不会对 === 造成问题)。

我的建议 - 两者都不使用。你需要编写自己的比较函数来真正解决这个混乱。

1赞 MAChitgarha 9/13/2018 #11

PHP数组和对象之间和在PHP数组和对象之间有两个区别,没有人提到:两个具有不同键排序的数组和对象。=====

两个具有不同键排序的数组

如果有两个数组,它们的键排序不同,但键值映射相等,则它们严格不同(即使用 )。如果您对数组进行键排序,并尝试将排序后的数组与原始数组进行比较,则可能会导致问题。===

例如:

$arrayUnsorted = [
    "you" => "you",
    "I" => "we",
];

$arraySorted = $arrayUnsorted;
ksort($arraySorted);

$arrayUnsorted == $arraySorted; // true
$arrayUnsorted === $arraySorted; // false

对象

请记住,主要规则是两个不同的对象永远不会严格相等。请看以下示例:

$stdClass1 = new stdClass();
$stdClass2 = new stdClass();
$clonedStdClass1 = clone $stdClass1;

$stdClass1 == $stdClass2; // true
$stdClass1 === $stdClass2; // false
$stdClass1 == $clonedStdClass1; // true
$stdClass1 === $clonedStdClass1; // false

: 将对象分配给另一个变量不会创建副本,而是创建对同一对象的引用。请看这里

注意:从 PHP7 开始,引入了匿名类。在上面的测试中,a 和 a 之间没有区别。new class {}new stdClass()

4赞 thomas 1/10/2021 #12

PHP 双倍等于:==

在大多数编程语言中,比较运算符 (==) 一方面检查数据类型,另一方面检查变量的内容是否相等。PHP 中的标准比较运算符 (==) 的行为不同。这会尝试在比较之前将两个变量转换为相同的数据类型,然后才检查这些变量的内容是否相同。得到以下结果:

<?php
    var_dump( 1 == 1 );     // true
    var_dump( 1 == '1' );   // true
    var_dump( 1 == 2 );     // false
    var_dump( 1 == '2' );   // false
    var_dump( 1 == true );  // true
    var_dump( 1 == false ); // false
?>

PHP 三重等于:===

此运算符还会检查变量的数据类型,仅当两个变量具有相同的内容和相同的数据类型时,才返回 (bool)true。因此,以下几点是正确的:

<?php
    var_dump( 1 === 1 );     // true
    var_dump( 1 === '1' );   // false
    var_dump( 1 === 2 );     // false
    var_dump( 1 === '2' );   // false
    var_dump( 1 === true );  // false
    var_dump( 1 === false ); // false
?>

阅读更多内容 PHP 中 == 和 === 有什么区别

1赞 Gufran Hasan 2/12/2021 #13

==(相等)和 ===(等于)之间的区别

PHP 提供了两个比较运算符来检查两个值的相等性。这两者之间的主要区别在于检查两个操作数的值是否为 。另一方面,检查值以及操作数的类型是 。'=='equal or not'==='equal or not

== (相等)

=== (等同)

示例 =>

<?php 
    $val1 = 1234;
    $val2 = "1234";
    var_dump($val1 == $val2);// output => bool(true)
    //It checks only operands value
?> 


<?php 
    $val1 = 1234;
    $val2 = "1234";
    var_dump($val1 === $val2);// output => bool(false)
    //First it checks type then operands value
?> 

如果我们键入 cast $val 2 to (int)$val 2 or (string)$val 1,则返回 true

   <?php 
        $val1 = 1234;
        $val2 = "1234";
        var_dump($val1 === (int)$val2);// output => bool(true)
        //First it checks type then operands value
    ?> 

  <?php 
        $val1 = 1234;
        $val2 = "1234";
        var_dump($val1 === (int)$val2);// output => bool(true)
        //First it checks type then operands value
    ?>