Các toán tử so sánh đẳng thức (== double bằng) và nhận dạng (=== ba bằng) khác nhau như thế nào?


509

Sự khác biệt giữa ==và là ===gì?

  • Làm thế nào chính xác làm việc ==so sánh lỏng lẻo làm việc?
  • Làm thế nào chính xác làm việc ===so sánh nghiêm ngặt làm việc?

Điều gì sẽ là một số ví dụ hữu ích?

Câu trả lời:


633

Sự khác biệt giữa =====

Sự khác biệt giữa ==toán tử bằng nhau lỏng lẻo và ===toán tử giống hệt nghiêm ngặt được giải thích chính xác trong hướng dẫn :

Toán tử so sánh

┌ ─ ─ Giới thiệu về giới tính của bạn.
Ví dụ │ Tên Kết quả
├ ─ ─ Giới thiệu về giới tính của bạn.
│ $ a == $ b │ Bằng nhau │ TRUE nếu $ a bằng $ b sau khi tung hứng. │
│ $ a === $ b │ Giống hệt │ THẬT nếu $ a bằng $ b và chúng cùng loại. │
└ ─ ─ Giới thiệu về giới tính của bạn.

Lỏng lẻo ==so sánh bình đẳng

Nếu bạn đang sử dụng ==toán tử hoặc bất kỳ toán tử so sánh nào sử dụng phép so sánh lỏng lẻo như !=, <>hoặc ==, bạn luôn phải xem xét bối cảnh để xem cái gì, ở đâu và tại sao một cái gì đó được chuyển đổi để hiểu điều gì đang xảy ra.

Chuyển đổi quy tắc

Bảng so sánh

Để tham khảo và ví dụ, bạn có thể xem bảng so sánh trong hướng dẫn :

So sánh lỏng lẻo với ==

┌ ─ ─ ┬ ┬───────
│ TRUE FALSE 1 0 -1 │ "1" │ "0" │ "-1" │ NULL │ mảng () "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 FUESE FALSE FALSE FALSE
"1" TRUE FALSE TRUE │ FALSE FALSE TRUE │ FALSE FALSE FALSE FALSE FALSE FALSE FALSE
│ "0" FALSE TRUE │ FALSE TRUE │ FALSE FALSE TRUE │ FALSE 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 TRUE │ TRUE │ FALSE TRUE
Mảng () FALSE TRUE │ FALSE FALSE FALSE FALSE FALSE TRUE │ TRUE SE FALSE FALSE
│ "php" TRUE FALSE FALSE TRUE │ FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
"" FALSE TRUE FALSE TRUE │ FALSE FALSE FALSE FALSE FALSE FALSE TRUE
└ ─ ─ ┴ ┴───────

Nghiêm ngặt ===so sánh giống hệt nhau

Nếu bạn đang sử dụng các ===nhà điều hành, hoặc bất kỳ toán tử so sánh khác trong đó sử dụng so sánh nghiêm ngặt như !==hoặc ===, sau đó bạn luôn có thể chắc chắn rằng các loại sẽ không kỳ diệu thay đổi, bởi vì sẽ không có chuyển đổi xảy ra. Vì vậy, với sự so sánh chặt chẽ, loại và giá trị phải giống nhau, không chỉ giá trị.

Bảng so sánh

Để tham khảo và ví dụ, bạn có thể xem bảng so sánh trong hướng dẫn :

So sánh nghiêm ngặt với ===

┌ ─ ─ ┬ ┬───────
│ TRUE FALSE 1 0 -1 │ "1" │ "0" │ "-1" │ NULL │ mảng () "php" │ ""
├ ─ ─ ┼ ┼───────
TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
FALSE FALSE TRUE │ FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
1 FALSE FALSE TRUE │ FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
0 FALSE FALSE FALSE TRUE │ FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
-1 FALSE FALSE FALSE FALSE TRUE │ FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
"1" FALSE FALSE FALSE FALSE FALSE TRUE │ FALSE FALSE FALSE FALSE FALSE FALSE FALSE
│ "0" FALSE FALSE FALSE FALSE FALSE FALSE TRUE │ FALSE FALSE FALSE FALSE FALSE FALSE
│ "-1" FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
NULL FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
Mảng () FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
│ "php" FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
"" FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE
└ ─ ─ ┴ ┴───────

66
Có ai khác thấy lạ rằng "000" == "0000" không?
nickf

36
Điều luôn làm tôi ngạc nhiên là false == mảng () và false == 0 nhưng mảng ()! = 0, vậy false == mảng ()! = / == 0? điều đó cảm thấy kỳ lạ với tôi
Pim Jager

4
@Pim ... tiếp tục: Hãy nhìn nó theo cách này: Đúc thành BOOL, bất kỳ giá trị nào chỉ phải rơi vào một trong hai mặt, truehoặc false. Thật dễ dàng để đúc. Tất cả các giá trị khác mặc dù có, cho tất cả các mục đích thực tế, hầu như không giới hạn kết hợp. Là "five" == 5? array(0) == 0? array(0,0,0) == 0? 0.0000000000000000000000000000000000000000000000000001 == array()?
lừa dối

12
@Raithlin, cẩn thận của mảng. bộ ba bằng falsecho các mảng khác nhau trong javascript, nhưng trueđối với PHP miễn là giá trị của chúng bằng nhau .
Pacerier

14
@Raithlin, Nhiều nhiều vấn đề khác. Trong JavaScript: "000" != "00" , "000" == null, "000" == false, "0x0" == false, array() == 0, false != null, array() != null, false == "0x0", false == "000". Trong PHP, đó là hành vi ngược lại: "000" == "00" , "000" != null, "000" != false, "0x0" != false, array() != 0, false == null, array() == null, false != "0x0", false != "000".
Pacerier

239

Toán tử == phôi giữa hai loại khác nhau nếu chúng khác nhau, trong khi toán tử === thực hiện 'so sánh an toàn kiểu'. Điều đó có nghĩa là nó sẽ chỉ trả về true nếu cả hai toán hạng có cùng loại và cùng giá trị.

Ví dụ:

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

Cảnh báo : hai trường hợp của cùng một lớp với các thành viên tương đương KHÔNG khớp với ===toán tử. Thí dụ:

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

3
Nitpick: === sẽ chỉ trả về true nếu cả hai toán hạng cùng loại và các giá trị bằng nhau =)
gnud

1
@gnud Đó chính xác là những gì anh ấy thể hiện trong ví dụ. Nếu chỉ là so sánh các loại thì nó sẽ chỉ được gọi là "so sánh kiểu".
Rob Stevenson-Leggett

3
Sau khi sử dụng PHP được 8 năm, ngày hôm qua là lần đầu tiên tôi bị cuốn vào một tình huống mà tôi nên sử dụng ===

3
=== đúng nếu chúng bằng nhau và có cùng loại. == đúng nếu chúng bằng nhau. ! = true nếu chúng không bằng nhau. ! == true nếu chúng không bằng nhau hoặc bằng nhau nhưng không cùng loại.
Jeremy C

1
Ngoài ra, sử dụng === nhanh hơn một chút so với == vì không cần chuyển đổi giá trị trước khi kiểm tra xem nó có bằng nhau không.
clauziere

88

Một bưc tranh đang gia ngan lơi noi:

==Biểu đồ bình đẳng đôi PHP :

nhập mô tả hình ảnh ở đây

===Biểu đồ ba đẳng thức PHP :

nhập mô tả hình ảnh ở đây

Mã nguồn để tạo ra những hình ảnh này:

https://github.com/sentientmachine/php_equality_charts

Thiền sư

Những người muốn giữ sự tỉnh táo của họ, không đọc thêm bởi vì điều này sẽ không có ý nghĩa gì, ngoại trừ việc nói rằng đây là cách mà sự điên rồ-fractal, của PHP được thiết kế.

  1. NAN != NANnhưng NAN == true.
  2. ==sẽ chuyển đổi toán hạng trái và phải thành số nếu trái là số. Vì vậy 123 == "123foo", nhưng"123" != "123foo"
  3. Một chuỗi hex trong dấu ngoặc kép đôi khi là một dấu phẩy và sẽ được tạo bất ngờ để nổi theo ý bạn, gây ra lỗi thời gian chạy.

  4. ==không phải là bắc cầu bởi vì "0"== 0, và 0 == ""nhưng"0" != ""

  5. Các biến PHP chưa được khai báo là sai, mặc dù PHP có cách biểu diễn các biến không xác định, tính năng đó bị vô hiệu hóa ==.
  6. "6" == " 6", "4.2" == "4.20"và, "133" == "0133"nhưng 133 != 0133. Nhưng "0x10" == "16""1e3" == "1000"phơi bày rằng chuyển đổi chuỗi bất ngờ thành bát phân sẽ xảy ra cả mà không có hướng dẫn hoặc sự đồng ý của bạn, gây ra lỗi thời gian chạy.

  7. False == 0, "", []"0".

  8. Khi số lượng đủ lớn, chúng là == Infinity.

  9. Một lớp học mới là == đến 1.

  10. Sai là giá trị nguy hiểm nhất vì Sai là == đối với hầu hết các biến khác, chủ yếu là đánh bại mục đích của nó.

Mong:

Nếu bạn đang sử dụng PHP, bạn sẽ không sử dụng toán tử bằng hai vì nếu bạn sử dụng ba số bằng, các trường hợp cạnh duy nhất phải lo lắng là NAN và các số gần đến vô cùng mà chúng được chuyển thành vô cùng. Với hai lần bằng nhau, bất cứ điều gì cũng có thể gây bất ngờ ==cho bất cứ điều gì hoặc, hoặc có thể gây bất ngờ đối với ý chí của bạn và !=với điều gì đó rõ ràng là bằng nhau.

Bất cứ nơi nào bạn sử dụng ==trong PHP đều có mùi mã xấu vì 85 lỗi trong đó bị phơi bày bởi các quy tắc truyền ngầm ẩn dường như được thiết kế bởi hàng triệu lập trình viên lập trình bằng chuyển động brownian.


Có thực sự là một ý tưởng tốt (cũng an toàn) để luôn luôn sử dụng ba bằng?
Chazy Chaz

3
Có, thuộc tính bắc cầu của ba bằng làm cho nó an toàn hơn và webscale.
Eric Leschinski

Làm thế nào một số có thể gần với vô cùng? [nổ não gif]
Tim

40

Liên quan đến JavaScript:

Toán tử === hoạt động giống như toán tử ==, nhưng nó yêu cầu các toán hạng của nó không chỉ có cùng giá trị mà còn có cùng kiểu dữ liệu.

Ví dụ: mẫu bên dưới sẽ hiển thị 'x và y bằng nhau', nhưng không 'x và y giống hệt nhau'.

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

Upvote, vì điều này dường như là chính xác cùng một tình huống cho php.
David nói phục hồi Monica

1
@DavidThomas Nó không phải chính xác same.See stackoverflow.com/questions/12598407/...
xdazz

22

Một bổ sung cho các câu trả lời khác liên quan đến so sánh đối tượng:

== so sánh các đối tượng bằng cách sử dụng tên của đối tượng và giá trị của chúng. Nếu hai đối tượng cùng loại và có cùng giá trị thành viên, $a == $bmang lại kết quả đúng.

=== so sánh id đối tượng bên trong của các đối tượng. Ngay cả khi các thành viên bằng nhau, $a !== $bnếu họ không chính xác cùng một đối tượng.

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

12

Nói một cách đơn giản nhất:

== kiểm tra nếu tương đương (chỉ giá trị)

=== kiểm tra nếu cùng (giá trị && loại)


Tương đương so với giống nhau: Tương tự

1 + 1 = 2 + 0 (tương đương)

1 + 1 = 1 + 1 (giống nhau)


Trong PHP:

true == 1 (đúng - tương đương về giá trị)

true === 1 (sai - không giống nhau về giá trị && type)

  • đúng là boolean
  • 1 là số nguyên

"=== kiểm tra nếu cùng (loại && loại)", không chính xác. Hai đối tượng stdClass có cùng loại 'đối tượng' (nghĩa là sử dụng gettype ()), nhưng PHP cho biết chúng là hai thứ khác nhau nếu bạn sử dụng so sánh nghiêm ngặt. Xem này .
MAChitgarha

8

Đó là tất cả về các loại dữ liệu. Lấy một BOOLví dụ (đúng hoặc sai):

truecũng bằng 1falsecũng bằng0

Các ==không quan tâm đến các kiểu dữ liệu khi so sánh: Vì vậy, nếu bạn đã có một biến đó là 1 (mà cũng có thể là true):

$var=1;

Và sau đó so sánh với ==:

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

Nhưng $varkhông thực sự bằng nhau true, phải không? Nó có giá trị int 1thay vào đó, lần lượt, bằng với true.

Với ===, các kiểu dữ liệu được kiểm tra để đảm bảo hai biến / đối tượng / bất cứ thứ gì đang sử dụng cùng loại.

Vì vậy, nếu tôi đã làm

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

điều kiện đó sẽ không đúng, vì $var !== truenó chỉ == true(nếu bạn hiểu ý tôi).

Tại sao bạn cần điều này?

Đơn giản - chúng ta hãy xem một trong các chức năng của PHP array_search()::

Các array_search()chức năng đơn giản là tìm kiếm một giá trị trong một mảng, và trả về chìa khóa của phần tử giá trị được tìm thấy trong. Nếu giá trị không thể được tìm thấy trong mảng, nó sẽ trả về sai . Nhưng, điều gì sẽ xảy ra nếu bạn đã thực hiện array_search()một giá trị được lưu trữ trong phần tử đầu tiên của mảng (sẽ có khóa mảng 0) .... array_search()hàm sẽ trả về 0 ... bằng với sai ..

Vì vậy, nếu bạn đã làm:

$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.
}

Vì vậy, bạn có thấy làm thế nào điều này có thể là một vấn đề bây giờ?

Hầu hết mọi người không sử dụng == falsekhi kiểm tra nếu một hàm trả về sai. Thay vào đó, họ sử dụng !. Nhưng trên thực tế, điều này hoàn toàn giống như sử dụng ==false, vì vậy nếu bạn đã làm:

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

Vì vậy, đối với những thứ như vậy, bạn sẽ sử dụng ===thay thế, để loại dữ liệu được kiểm tra.


8

Một ví dụ là thuộc tính cơ sở dữ liệu có thể là null hoặc "":

$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

7

php == là toán tử so sánh so sánh giá trị của các biến. Nhưng === so sánh giá trị và kiểu dữ liệu.

Ví dụ,

<?php 
  $var1 = 10;
  $var2 = '10';

  if($var1 == $var2) {
    echo 'Variables are equal';
  } else {
    echo 'Variables are not equal';
  }
?>

Trong trường hợp này, đầu ra sẽ là 'Biến bằng nhau', mặc dù kiểu dữ liệu của chúng khác nhau.

Nhưng nếu chúng ta sử dụng === thay vì ==, đầu ra sẽ là 'Biến không bằng nhau'. Đầu tiên php so sánh giá trị của biến và sau đó là kiểu dữ liệu. Ở đây các giá trị là như nhau, nhưng các loại dữ liệu là khác nhau.


6

Được x = 5

1) Toán tử: == là "bằng". x == 8là sai
2) Toán tử: === là "chính xác bằng" (giá trị và loại) x === 5là đúng, x === "5"là sai


3
$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

Hãy cẩn thận. Đây là một vấn đề khét tiếng.

// 'test' is found at position 0, which is interpreted as the boolean 'false'
if (strpos('testing', 'test')) {
    // code...
}

so với

// true, as strict comparison was made (0 !== false)
if (strpos('testing', 'test') !== false) {
    // code...
}

3

Nói tóm lại, === hoạt động theo cách tương tự mà == thực hiện trong hầu hết các ngôn ngữ lập trình khác.

PHP cho phép bạn thực hiện các so sánh không thực sự có ý nghĩa. Thí dụ:

$y = "wauv";
$x = false;
if ($x == $y)
    ...

Mặc dù điều này cho phép một số "phím tắt" thú vị, bạn nên cẩn thận vì một hàm trả về thứ gì đó không nên (như "lỗi" thay vì số) sẽ không bị bắt và bạn sẽ không biết chuyện gì đã xảy ra.

Trong PHP, == so sánh các giá trị và thực hiện chuyển đổi loại nếu cần thiết (ví dụ: chuỗi "12343sdfjskfjds" sẽ trở thành "12343" trong so sánh số nguyên). === sẽ so sánh giá trị AND loại và sẽ trả về false nếu loại không giống nhau.

Nếu bạn xem trong hướng dẫn PHP, bạn sẽ thấy rất nhiều hàm trả về "false" nếu hàm bị lỗi, nhưng chúng có thể trả về 0 trong một kịch bản thành công, đó là lý do tại sao chúng khuyên bạn nên thực hiện "if (function ()! == sai) "để tránh sai lầm.


1
Cần lưu ý rằng ngoài các "phím tắt" đó, hành vi bất thường của toán tử == đã được biết là mở các lỗ hổng bảo mật, ví dụ như một diễn đàn PHP phổ biến nơi có thể đặt giá trị băm mật khẩu cookie thành đúng, phá vỡ xác thực if (cơ sở dữ liệu == cookiehash).
David

3

Vài ví dụ

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.

PS

== Chỉ so sánh giá trị, nó sẽ không bận tâm về các loại dữ liệu

so với

=== So sánh các giá trị và kiểu dữ liệu


Có vấn đề gì với câu trả lời này?
Mohit Tanwani

2

Bạn sẽ sử dụng === để kiểm tra xem một hàm hoặc biến là sai thay vì chỉ tương đương với false (không hoặc chuỗi rỗng).

$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;
}

Trong trường hợp này, strpose sẽ trả về 0, tương đương với sai trong thử nghiệm

if ($pos == false)

hoặc là

if (!$pos)

đó không phải là những gì bạn muốn ở đây.


2

Về việc khi nào nên sử dụng cái này hơn cái kia, ví dụ như fwrite()hàm trong PHP.

Hàm này ghi nội dung vào một luồng tệp. Theo PHP, " fwrite()trả về số lượng byte được ghi hoặc FALSE bị lỗi.". Nếu bạn muốn kiểm tra xem cuộc gọi chức năng có thành công hay không, phương pháp này là thiếu sót:

if (!fwrite(stuff))
{
    log('error!');
}

Nó có thể trả về 0 (và được coi là thành công) và tình trạng của bạn vẫn được kích hoạt. Cách đúng sẽ là:

if (fwrite(stuff) === FALSE)
{
    log('error!');
}

2

PHP là một ngôn ngữ gõ lỏng lẻo. Sử dụng toán tử kép bằng nhau cho phép kiểm tra lỏng một biến.

Việc kiểm tra một cách lỏng lẻo một giá trị sẽ cho phép một số giá trị tương tự, nhưng không bằng nhau, tương đương nhau:

  • ''
  • vô giá trị
  • sai
  • 0

Tất cả các giá trị này sẽ tương đương như nhau bằng cách sử dụng toán tử kép bằng nhau.


1

Các biến có một loại và một giá trị.

  • $ var = "test" là một chuỗi chứa "test"
  • $ var2 = 24 là giá trị vhose nguyên là 24.

Khi bạn sử dụng các biến này (trong PHP), đôi khi bạn không có loại tốt. Ví dụ, nếu bạn làm

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

PHP phải chuyển đổi ("sang cast") $ var thành số nguyên. Trong trường hợp này, "$ var == 1" là đúng bởi vì bất kỳ chuỗi không trống nào được chuyển thành 1.

Khi sử dụng ===, bạn kiểm tra xem giá trị VÀ LOẠI có bằng nhau không, vì vậy "$ var === 1" là sai.

Điều này rất hữu ích, ví dụ, khi bạn có một hàm có thể trả về false (lỗi) và 0 (kết quả):

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

Mã này sai như thể myFunction()trả về 0, nó được chuyển thành false và bạn dường như có lỗi. Mã chính xác là:

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

bởi vì thử nghiệm là giá trị trả về "là boolean và là false" và không "có thể được chuyển thành false".


liên quan đến các chuỗi không trống, điều đó thực sự không đúng. "a" == 0 là ĐÚNG.
nickf

1

Các ===nhà điều hành có nghĩa vụ phải so sánh chính xác bình đẳng nội dung trong khi các ==nhà điều hành sẽ so sánh bình đẳng ngữ nghĩa. Đặc biệt nó sẽ ép các chuỗi thành số.

Bình đẳng là một chủ đề rộng lớn. Xem bài viết Wikipedia về bình đẳng .


1
<?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);
?>

1

Tất cả các câu trả lời cho đến nay đều bỏ qua một vấn đề nguy hiểm với ===. Nó đã được ghi nhận khi truyền, nhưng không nhấn mạnh, số nguyên và số kép là các loại khác nhau, do đó, đoạn mã sau:

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

cho:

 equal
 not equal

Lưu ý rằng đây KHÔNG phải là trường hợp "lỗi làm tròn". Hai số chính xác bằng với bit cuối cùng, nhưng chúng có các loại khác nhau.

Đây là một vấn đề khó chịu vì một chương trình sử dụng === có thể chạy rất vui trong nhiều năm nếu tất cả các số đủ nhỏ (trong đó "đủ nhỏ" phụ thuộc vào phần cứng và hệ điều hành bạn đang chạy). Tuy nhiên, nếu tình cờ, một số nguyên đủ lớn để được chuyển đổi thành gấp đôi, loại của nó được thay đổi "mãi mãi" ngay cả khi một hoạt động tiếp theo hoặc nhiều hoạt động có thể đưa nó trở lại một số nguyên nhỏ về giá trị. Và, nó trở nên tồi tệ hơn. Nó có thể lây lan - nhiễm trùng hai lần có thể truyền qua bất cứ thứ gì nó chạm vào, mỗi lần tính toán.

Trong thế giới thực, điều này có khả năng là một vấn đề trong các chương trình xử lý ngày ngoài năm 2038 chẳng hạn. Tại thời điểm này, dấu thời gian UNIX (số giây kể từ 1970-01-01 00:00:00 UTC) sẽ yêu cầu nhiều hơn 32 bit, do đó, đại diện của chúng sẽ "chuyển đổi" một cách kỳ diệu lên gấp đôi trên một số hệ thống. Do đó, nếu bạn tính chênh lệch giữa hai lần, bạn có thể kết thúc với một vài giây, nhưng là gấp đôi, thay vì kết quả số nguyên xảy ra trong năm 2017.

Tôi nghĩ rằng điều này là tồi tệ hơn nhiều so với chuyển đổi giữa các chuỗi và số bởi vì nó là tinh tế. Tôi thấy thật dễ dàng để theo dõi chuỗi là gì và số là gì, nhưng theo dõi số bit trong một số nằm ngoài tôi.

Vì vậy, trong các câu trả lời ở trên có một số bảng hay, nhưng không có sự phân biệt giữa 1 (dưới dạng số nguyên) và 1 (gấp đôi tinh tế) và 1.0 (gấp đôi rõ ràng). Ngoài ra, lời khuyên mà bạn nên luôn luôn sử dụng === và không bao giờ == là không tốt vì đôi khi === sẽ thất bại khi == hoạt động đúng. Ngoài ra, JavaScript không tương đương về mặt này vì nó chỉ có một loại số (bên trong nó có thể có các cách biểu diễn bit-khôn ngoan khác nhau, nhưng nó không gây ra vấn đề cho ===).

Lời khuyên của tôi - sử dụng không. Bạn cần phải viết chức năng so sánh của riêng bạn để thực sự sửa chữa mớ hỗn độn này.


0

Có hai sự khác biệt giữa =====trong các mảng và đối tượng PHP mà tôi nghĩ không đề cập ở đây; hai mảng với các loại khóa và đối tượng khác nhau.

Hai mảng với các loại khóa khác nhau

Nếu bạn có một mảng với một loại sắp xếp khóa và một mảng khác với một loại khóa khác, thì chúng hoàn toàn khác nhau (tức là sử dụng ===). Điều đó có thể gây ra nếu bạn sắp xếp khóa một mảng và cố gắng so sánh mảng đã sắp xếp với mảng ban đầu.

Ví dụ, hãy xem xét một mảng trống. Đầu tiên, chúng tôi cố gắng đẩy một số chỉ mục mới vào mảng mà không có bất kỳ sắp xếp đặc biệt nào. Một ví dụ tốt sẽ là một mảng với các chuỗi là các khóa. Bây giờ đi sâu vào một ví dụ:

// Define an array
$arr = [];

// Adding unsorted keys
$arr["I"] = "we";
$arr["you"] = "you";
$arr["he"] = "they";

Bây giờ, chúng ta có một mảng các khóa không được sắp xếp (ví dụ: 'anh ấy' đến sau 'bạn'). Hãy xem xét cùng một mảng, nhưng chúng tôi đã sắp xếp các khóa theo thứ tự bảng chữ cái:

// Declare array
$alphabetArr = [];

// Adding alphabetical-sorted keys
$alphabetArr["I"] = "we";
$alphabetArr["he"] = "they";
$alphabetArr["you"] = "you";

Mẹo : Bạn có thể sắp xếp một mảng theo khóa bằng hàm ksort () .

Bây giờ bạn có một mảng khác với một loại khóa khác với loại đầu tiên. Vì vậy, chúng tôi sẽ so sánh chúng:

$arr == $alphabetArr; // true
$arr === $alphabetArr; // false

Lưu ý : Có thể rõ ràng, nhưng so sánh hai mảng khác nhau bằng cách sử dụng so sánh nghiêm ngặt luôn cho kết quả false. Tuy nhiên, hai mảng tùy ý có thể bằng ===hoặc không sử dụng .

Bạn sẽ nói: "Sự khác biệt này là không đáng kể". Sau đó, tôi nói đó là một sự khác biệt và nên được xem xét và có thể xảy ra bất cứ lúc nào. Như đã đề cập ở trên, sắp xếp các khóa trong một mảng là một ví dụ tốt về điều đó.

Các đối tượng

Hãy ghi nhớ, hai đối tượng khác nhau không bao giờ nghiêm ngặt - bằng nhau . Những ví dụ này sẽ giúp:

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

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

Lưu ý : Việc gán một đối tượng cho một biến khác không tạo ra một bản sao - thay vào đó, nó tạo ra một tham chiếu đến cùng một vị trí bộ nhớ với đối tượng. Xem ở đây .

Lưu ý : Kể từ PHP7, các lớp ẩn danh đã được thêm vào. Từ kết quả, không có sự khác biệt giữa new class {}new stdClass()trong các thử nghiệm ở trên.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.