Tại sao PHP coi 0 là một chuỗi?


111

Tôi có đoạn mã sau:

$item['price'] = 0;
/* Code to get item information goes in here */
if($item['price'] == 'e') {
    $item['price'] = -1;
}

Nó nhằm khởi tạo giá mặt hàng về 0 và sau đó lấy thông tin về nó. Nếu giá được thông báo là 'e', ​​nó có nghĩa là trao đổi thay vì bán, được lưu trữ trong cơ sở dữ liệu dưới dạng số âm.

Cũng có khả năng để giá là 0, vì mặt hàng là một phần thưởng hoặc vì giá sẽ được đặt trong giây phút sau đó.

Tuy nhiên, bất cứ khi nào giá không được đặt, khiến nó có giá trị ban đầu là 0, ifvòng lặp được chỉ ra ở trên sẽ đánh giá là đúng và giá được đặt thành -1. Tức là, nó coi 0 bằng 'e'.

làm như thế nào để giải thích chuyện này?

Khi giá được cung cấp là 0 (sau khi khởi tạo), hành vi sẽ thất thường: đôi khi giá trị được đánh giá là đúng, đôi khi giá trị được đánh giá là sai. *


1
Tôi thấy rằng việc sử dụng ba === thay vì gấp đôi == mang lại hành vi mong đợi. Nhưng nó vẫn là kỳ lạ.
Sérgio Domingues,

2
(tham khảo) đủ giải thích trong hướng dẫn sử dụng PHP tại chương Loại Juggling và minh họa trong So sánh Loại Bảng
Gordon

1
Nếu loại chuỗi duy nhất có thể là 'e', ​​bạn có thể kiểm tra is_string ($ item ["price"]) không? Điều đó sẽ hiệu quả hơn một chút so với ===. [cần dẫn nguồn]
Jimmie Lin

trong so sánh yếu giữa chuỗi và số nguyên , chuỗi được chuyển đổi thành số nguyên (thay vì số nguyên được "thăng cấp" thành chuỗi). if((string)$item['price'] == 'e')sửa chữa các hành vi kỳ quặc. Xem stackoverflow.com/a/48912540/1579327 để biết thêm chi tiết
Paolo

Vui lòng lưu ý một trường hợp khác trong nhận xét bên dưới của @Paolo trong đó 0 (số nguyên) bằng bất kỳ chuỗi nào khác khi sử dụng toán tử dấu bằng kép.
Haitham Sweilem

Câu trả lời:


113

Bạn đang làm ==mà sắp xếp các loại cho bạn.

0là một int, vì vậy trong trường hợp này, nó sẽ chuyển 'e'thành một int. Cái nào không thể phân tích cú pháp là một và sẽ trở thành 0. Một chuỗi '0e'sẽ trở thành 0và sẽ khớp!

Sử dụng ===


14
Một nhược điểm khác của so sánh lỏng lẻo.
MC Emperor

5
Mánh khôn. Chỉ cần tình cờ gặp cái này và ngạc nhiên tại sao chuỗi == 0. Tôi phải nhớ điều đó.
Grzegorz

2
Tôi cũng đang vò đầu bứt tai về vấn đề này khi tôi đang lặp trên các khóa chuỗi, nhưng mảng có mục chỉ mục '0' ban đầu liên tục dẫn đến đúng trong lần so sánh khóa chuỗi đầu tiên. Tôi đã như thế nào? Làm thế nào trong ... vì vậy, đủ chắc chắn, câu trả lời này đã làm sáng tỏ điều đó! Tôi ngạc nhiên là toàn bộ câu hỏi này không có MỘT câu trả lời nào được chấp nhận. Chỉ đi để hiển thị một số người hỏi câu hỏi là những kẻ giật dây.
IncredibleHat

48

Điều này là do cách PHP thực hiện thao tác so sánh mà ==toán tử so sánh biểu thị:

Nếu bạn so sánh một số với một chuỗi hoặc phép so sánh liên quan đến các chuỗi số, thì mỗi chuỗi được chuyển đổi thành một số và phép so sánh được thực hiện ở dạng số. […] Việc chuyển đổi kiểu không diễn ra khi so sánh ===hoặc !==vì điều này liên quan đến việc so sánh kiểu cũng như giá trị.

Vì toán hạng đầu tiên là số ( 0) và toán hạng thứ hai là chuỗi ( 'e'), chuỗi cũng được chuyển đổi thành số (xem thêm bảng So sánh với các loại khác nhau ). Trang thủ công về kiểu dữ liệu chuỗi đã xác định cách thực hiện chuyển đổi chuỗi thành số :

Khi một chuỗi được đánh giá trong ngữ cảnh số, giá trị và kiểu kết quả được xác định như sau.

Nếu chuỗi không chứa bất kỳ ký tự nào trong số các ký tự ' .', ' e' hoặc ' E' và giá trị số phù hợp với giới hạn kiểu số nguyên (như được xác định bởi PHP_INT_MAX), chuỗi sẽ được đánh giá là số nguyên. Trong tất cả các trường hợp khác, nó sẽ được đánh giá là một phao.

Trong trường hợp này, chuỗi là 'e'và do đó nó sẽ được đánh giá là một float:

Giá trị được cung cấp bởi phần ban đầu của chuỗi. Nếu chuỗi bắt đầu bằng dữ liệu số hợp lệ, đây sẽ là giá trị được sử dụng. Nếu không, giá trị sẽ là 0(không). Dữ liệu số hợp lệ là một dấu tùy chọn, theo sau là một hoặc nhiều chữ số (tùy chọn chứa dấu thập phân), theo sau là số mũ tùy chọn. Số mũ là một ' e' hoặc ' E' theo sau bởi một hoặc nhiều chữ số.

'e'không bắt đầu bằng dữ liệu số hợp lệ, nó đánh giá là float 0.


3
php thiết kế hầu hết mọi thứ để có thể dễ dàng so sánh và sau đó ném vào một vài gotchas chỉ để phá hỏng ngày của chúng ta. Điều này không phù hợp với phần còn lại của triết lý thiết kế PHP. Trừ khi lừa dối thì mới có triết học ???
user3338098,

1
đặc biệt là kể từ khi "e" phôi là true và "" phôi false
user3338098

20
"ABC" == 0

đánh giá trueđầu tiên "ABC" được chuyển đổi thành số nguyên và 0 sau đó nó được so sánh với 0.

Đây là một hành vi kỳ lạ của ngôn ngữ PHP: thông thường người ta sẽ mong đợi 0được thăng cấp thành chuỗi "0"và sau đó được so sánh "ABC"với một kết quả false. Có lẽ đó là những gì xảy ra trong các ngôn ngữ khác như JavaScript nơi mà so sánh yếu "ABC" == 0đánh giá false.

Thực hiện một phép so sánh chặt chẽ sẽ giải quyết được vấn đề:

"ABC" === 0

đánh giá false.

Nhưng nếu tôi cần so sánh số dưới dạng chuỗi với số thì sao?

"123" === 123

đánh giá falsevì thuật ngữ bên trái và bên phải thuộc loại khác nhau.

Những gì thực sự cần thiết là một so sánh yếu mà không có cạm bẫy của việc tung hứng kiểu PHP.

Giải pháp là quảng bá rõ ràng các điều khoản thành chuỗi và sau đó thực hiện so sánh (chặt chẽ hay yếu không còn quan trọng nữa).

(string)"123" === (string)123

true

trong khi

(string)"123" === (string)0

false


Áp dụng cho mã gốc:

$item['price'] = 0;
/*code to get item information goes in here*/
if((string)$item['price'] == 'e') {
    $item['price'] = -1;
}

9

Toán tử == sẽ cố gắng so khớp các giá trị ngay cả khi chúng thuộc các kiểu khác nhau. Ví dụ:

'0' == 0 will be true

Nếu bạn cũng cần so sánh kiểu, hãy sử dụng toán tử ===:

'0' === 0 will be false

9

Vấn đề của bạn là toán tử bằng kép, sẽ gõ thành viên bên phải thành loại bên trái. Sử dụng nghiêm ngặt nếu bạn thích.

if($item['price'] == 'e') {
    $item['price'] = -1;
}

Hãy quay lại mã của bạn (đã sao chép ở trên). Trong trường hợp này, trong hầu hết các trường hợp, $ item ['price'] là một số nguyên (rõ ràng là trừ khi nó bằng e). Như vậy, theo luật của PHP, PHP sẽ nhập "e"thành số nguyên, kết quả là int(0). (Không tin tôi? <?php $i="e"; echo (int)$i; ?>).

Để dễ dàng loại bỏ điều này, hãy sử dụng toán tử ba bằng (so sánh chính xác), sẽ kiểm tra kiểu và sẽ không đánh máy ngầm.

PS: một thực tế thú vị về PHP: a == bkhông ngụ ý điều đó b == a. Lấy ví dụ của bạn và đảo ngược nó: if ("e" == $item['price'])sẽ không bao giờ thực sự được đáp ứng miễn là $ item ['price'] luôn là một số nguyên.


7

Có một phương pháp khá tiện dụng trong PHP để xác thực hỗn hợp của "0", "false", "off" là == false và "1", "on", "true" là == true mà thường bị bỏ qua. Nó đặc biệt hữu ích để phân tích cú pháp các đối số GET / POST:

filter_var( $item['price'], FILTER_VALIDATE_BOOLEAN );

Nó không liên quan hoàn toàn đến trường hợp sử dụng này nhưng với sự giống nhau và thực tế, đây là kết quả tìm kiếm có xu hướng tìm thấy khi đặt câu hỏi xác thực (chuỗi) "0" là sai mà tôi nghĩ nó sẽ giúp ích cho người khác.

http://www.php.net/manual/en/filter.filters.validate.php


6

Bạn nên sử dụng ===thay vì== , vì toán tử thông thường không so sánh các loại. Thay vào đó, nó sẽ cố gắng đánh máy các mục.

Trong khi đó các ===loại mặt hàng đang cân nhắc.

  • === có nghĩa là "bằng",
  • == có nghĩa là "eeeeh .. kinda trông giống như"

1
Tôi hiểu rồi. Tính năng này hiện đã hoạt động (với kiểu đánh máy):if((string)$item['price']=='e'){ $item['price'] = -1; }
Sérgio Domingues,

nhưng bạn không nên làm như vậy. chỉ cần sử dụng các ===nhà điều hành
tereško

3

Tôi nghĩ tốt nhất là nên thể hiện bằng những ví dụ tôi đã làm, trong khi gặp phải hành vi kỳ lạ tương tự. Xem trường hợp thử nghiệm của tôi và hy vọng nó sẽ giúp bạn hiểu hành vi tốt hơn:

// Normal comparison using the == Operator
echo (0 == "0"); // true
echo (0 == "a"); // true
echo (0 == "safta!"); // true
echo (1000 == "bla"); // false. It appears that PHP has a weird behavior only with the number / string 0 / "0" according to the past 3 examples.
echo (23 == "23"); // true. So as we said, PHP has a problem (not a problem but weird behavior) only when the number / string 0 (or "0") is present
echo (23 == "24"); // false. values aren't equal (unlike last example). The type is less relevant with the == operator as we can see.

// Now using the === and !== Operators
echo ("0" === 0); // false, since === requires both value and type to be the same. Here, type is different (int vs string)
echo ("0" !== 0); // true because they aren't the same in terms of === comparison (type is different and that's why it's true)
echo ("bla" === "blaa"); // false because the values are not the same. The type is the same, but === checks for both equal type and equal value.

//Now using casting and === Operator:
echo ((string)123 === "123"); // true. The casting of the int 123 to string changed it to "123" and now both variables have same value and are of same type
echo ((int)"123" === 123); // true. The casting of the string 123 to int, changed it to int, and now both variables are of same value and type (which is exactly what the === operator is looking for)

// Now using casting and == Operator. Basically, as we've seen above, the == care less for the
// type of var, but more to the value. So the casting is less relevant here, because even
// without casting, like we saw earlier, we can still compare string to int with the == operator
// and if their value is same, we'll get true. Either way, we will show that:
echo ((string)123 == "123"); // true. The casting of the int 123 to string changed it to "123" and now both vars have same value and are of same type
echo ((int)"123" == 123); // true. The casting of the string 123 to int, changed it to int, and now both vars are of same value and type (which is exactly what the === operator is looking for)

Bài kiểm tra tuyệt vời, tôi đã làm như vậy nhưng tôi đã làm một bảng đẹp từ. xem câu trả lời của tôi
IAMTHEBEST

0

Về cơ bản, luôn sử dụng ===toán tử, để đảm bảo an toàn cho loại.

Nhập mô tả hình ảnh tại đây

Nhập mô tả hình ảnh tại đây

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.