2010-07-18 23 views
12

Tôi tình cờ gặp một đoạn mã PHP rất lạ. Ai đó có thể giải thích lý do tại sao điều này xảy ra? ***** ĐIỂM THƯỞNG ***** nếu bạn có thể cho biết lý do tại sao điều này hữu ích.So sánh giá trị php rất không hợp lý

<?php 
if(0=='a'){ 
    print ord(0)." should NEVER equal ".ord('a')."<br>"; 
} 
if(false==0){ 
     print "false==0<br>"; 
} 
if('a'==false){ 
     print "a==false<br>"; 
} 
?> 

Và kết quả đầu ra:

48 should NEVER equal 97 
false==0 
+1

Cũng giống như trong Javascript, so sánh giữa các loại khác nhau có thể không được chuyển đổi. Đó là sự kinh hoàng của sự ép buộc kiểu. – JAL

Trả lời

33

Trong PHP, 'a' không phải là ký tự ASCII a, nhưng chuỗi a. Trong một ngữ cảnh số, nó bằng 0. Ví dụ intval('a') dẫn đến giá trị là 0.

Điều này rất hữu ích vì PHP chủ yếu được sử dụng để xử lý văn bản và có thể muốn thử nghiệm (123 == '123'), điều này đúng. Và cho rằng một số trong dấu ngoặc kép đơn (hoặc đôi) được coi là số, nó không có ý nghĩa đối với một chuỗi không có giá trị số được coi là bất kỳ thứ gì khác ngoài 0.

Oh yeah, một nữa Điều. 'a' trong ngữ cảnh boolean là đúng, không sai. Tôi tin rằng điều này làm cho một số loại văn bản xử lý tự nhiên hơn, nhưng tôi thành thật không thể nghĩ ra một ví dụ vào cuối giờ này.

+0

Vâng, nó giống như lấy ''a' + 0', vì 'a' không phải là một số, nó đơn giản bị bỏ và thêm vào 0, kết quả là 0, vì Số nguyên có độ ưu tiên truyền cao hơn Chuỗi. – animuson

+0

***** THƯỞNG ĐIỂM THƯỞNG ***** được trao. Cảm ơn câu trả lời. – rook

3

ord() mất nhân vật, vì vậy PHP biến 0 vào '0'. Và 0 bằng false, mặc dù nó không giống nhau (===).

8

Vâng, luôn có PHP type cheat sheet cho điều đó!

+0

+1 rất tuyệt vời !!! – rook

+0

Wow, tôi không bao giờ nhận ra rỗng() có nghĩa là isfalse() và is_null() có nghĩa là isnotset(). – aib

7

Đây là nguyên tắc cơ bản của ngôn ngữ yếu/được nhập động được gọi là type juggling. Các loại sẽ được truyền sang các loại khác trong một số trường hợp nhất định. Khi bạn so sánh chuỗi với một số, chuỗi sẽ được chuyển thành một số. Khi so sánh bất kỳ thứ gì với boolean, giá trị đó sẽ được chuyển thành boolean.

Therearerulesforeverytype như thế nào nó sẽ bị quăng vào loại khác hoặc làm thế nào nó compares với các loại khác. 'a' xảy ra để được chuyển đổi thành 0 khi truyền đến một số (sự lựa chọn hợp lý duy nhất, thực sự). Để tránh việc truyền kiểu này, hãy thử nghiệm không với toán tử bình đẳng ==, nhưng với identity operator===.

James pointed out, điều này rất hữu ích vì PHP thỏa thuận rất nhiều với các chuỗi thực sự là số. Ví dụ: biểu mẫu HTML chỉ gửi chuỗi, ngay cả khi giá trị là một số. Nó cũng cho phép một số mã thực sự ngắn gọn, như:

$result = someOperation(); 
if (!$result) { 
    // $result may be null, false, 0, '' or array(), 
    // all of which we're not interested in 
    error(); 
} 

Điều này cũng có nghĩa là bạn phải cẩn thận về những gì cần kiểm tra trong trường hợp nào đó, vì giá trị có thể bất ngờ xảy ra. Và thừa nhận, 'a' == 0 trong chính nó thực sự là một pitfall của juggling loại hơn là hữu ích. Đó là một trong những tình huống mà bạn phải cẩn thận và kiểm tra như if (is_numeric($var) && $var == 0).

1

Kiểm tra PHP type comparison tables từ hướng dẫn. Đó là một điều thực sự hữu ích để có gần trong tay cho đến khi bạn đã nội bộ hóa nó và đã vô giá cho sự hiểu biết của tôi về chính xác những gì sẽ đánh giá đúng và khi nào.

Những người khác đã trả lời cốt lõi của câu hỏi, nhưng tôi nghĩ rằng điều quan trọng là phải nói rằng trong PHP, chuỗi không trống rỗng duy nhất không đánh giá là "true" với toán tử == là "0" là PHP xử lý bất kỳ chuỗi nào chỉ chứa các số dưới dạng số nguyên hoặc dấu phẩy.

Lý do cho điều này là PHP được nhập khá lỏng lẻo và cố gắng cho phép số nguyên, chuỗi, phao nổi và giá trị boolean có thể hoán đổi cho nhau. Một ví dụ thực tế và ví dụ cực kỳ phổ biến về điều này là nếu bạn đang sử dụng các hàm mysql hoặc PDO, các chuỗi được trả lại cho mọi thứ, ngay cả khi cột bên dưới là một số nguyên.

Xem xét sql sau:

CREATE TABLE `test`.`pants` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , 
`some_other_int` INT NOT NULL 
) ENGINE = InnoDB; 

INSERT INTO `test`.`pants` (`id`, `some_other_int`) 
VALUES ('1', '1'), ('2', '0'); 

Và đoạn mã sau: "lĩnh vực x không phải là một chuỗi"

<?php 

$c = mysql_connect('127.0.0.1', 'user', 'password'); 
mysql_select_db('test', $c); 
$r = mysql_query('SELECT * FROM pants', $c); 

while ($row = mysql_fetch_assoc($r)) { 
    var_dump($row); 
    foreach($row as $k=>$v) { 
     if (!is_string($v)) 
      echo "field {$v} was not a string!\n"; 
    } 
} 

Các tin nhắn là không bao giờ được in, mặc dù mỗi cột trong cơ sở dữ liệu là một số nguyên. Giả sử bạn muốn thực sự sử dụng hàng thứ hai trong bảng đó.

<?php 
$id = 2; 
$r = mysql_query(sprintf('SELECT * FROM pants WHERE id=%s', mysql_real_esacpe_string($id)), $c); 
$row = mysql_fetch_assoc($r); 

// this is the important bit 
if (0 == $row['some_other_int']) { 
    echo "It was zero!"; 
} 

Nếu chuỗi "0" không được coi là số nguyên 0 để so sánh, mã trên sẽ không bao giờ in "Số không bằng 0!". Lập trình viên sẽ được yêu cầu chịu trách nhiệm về việc tung ra loại giá trị xuất phát từ cơ sở dữ liệu. Điều này là không mong muốn cho một ngôn ngữ lỏng lẻo.

Tính bình đẳng cao bao gồm loại được kiểm tra bằng cách sử dụng toán tử "Thực sự, thực sự, trung thực với thần", được biểu thị bằng ký hiệu "===".

1

Tôi không thấy như thế nào ('a' == 0) là hữu ích

$var = '123abc'; 

if (123 == $var) 
{ 
    echo 'Whoda thunk it?'; 
} 

Nó đi xuống đến quy tắc chuyển đổi tiềm ẩn của PHP.

Tôi không suy nghĩ về một ví dụ thực tế, nhưng đó là lý do cơ bản khiến bạn thấy hành vi đó.

Mở rộng:

Trong ví dụ của bạn, 'a' được chuyển thành 0 (0) để so sánh. Hãy tưởng tượng rằng với mục đích so sánh, nó tương đương với '0a'. (Đó là số không số, không phải là chữ 'o').

Tiếp tục mở rộng:

tôi nghĩ là có một trường hợp ví dụ sử dụng tốt cho việc này trong cuốn hướng dẫn, nhưng tôi không thể tìm thấy nó. Những gì tôi đã gặp phải sẽ giúp làm sáng tỏ tình trạng "phi lý" này.

PHP là ngôn ngữ lập trình đầu tiên và quan trọng nhất là ngôn ngữ lập trình . Vì Web là không được nhập và mọi thứ đều là một chuỗi, Tôi phải làm những việc hơi một cách khác nhau để sớm làm cho PHP thực hiện những gì mọi người mong đợi. Cụ thể, "123" == 123 cần phải đúng theo thứ tự để không phải nhập mỗi lần nhập đầu vào số người dùng.

http://bugs.php.net/bug.php?id=48012

Điều đó không chính xác trả lời các câu hỏi, nhưng nó trỏ theo hướng chung.

1

PHP là ngôn ngữ được nhập lỏng lẻo và cho phép bạn so sánh các giá trị của các loại khác nhau mà không bị lỗi, điều này rất dễ sử dụng nhưng như bạn thấy có thể gây ra một số kết quả logic nhưng lạ.

ví dụ đầu tiên của bạn:

if(0=='a'){ 
    print ord(0)." should NEVER equal ".ord('a')."<br>"; 
} 

Khi hai loại khác nhau của các giá trị được so sánh, một giá trị là lần đầu tiên biến thành cùng loại như khác thông qua một dàn diễn viên và sau đó so sánh. Trong ví dụ về Int và String chuỗi được chuyển đổi thành Int. Khi PHP biến một ký tự thành một chuỗi, tất cả các ký tự số đầu tiên và sau đó chops của phần còn lại: tức là '123123afraa' trở thành 123123, '9a9' trở thành 9. Nếu chuỗi không bắt đầu bằng số, thì giá trị của nó là 0

Ví dụ của bạn thực sự là: 0 === (chuỗi) 'a' thực sự là 0 === 0 vì 'a' không bắt đầu bằng số. Tôi nghĩ bạn đang mong đợi PHP trả về giá trị của 'a' trong ASCII mà nó không có! Điều này thực sự hữu ích để khử trùng các chuỗi, php hiếm khi cần để đối phó với các giá trị ascii nó là quá cao cấp cho điều đó. (Để tạo trang web!)

Khi chuỗi được so sánh với giá trị boolean '' hoặc '0' là sai, tất cả các giá trị khác đều đúng. Này rất hữu ích để bạn có thể kiểm tra xem một giá trị là 'trống':

url http://domain.com/?foo=

if ($ _GET [ 'foo'])) { // do something}

Khi một số nguyên được so sánh với một boolean các giá trị của 0 là false các giá trị khác là đúng, điều này là khá chuẩn.

Vì vậy, tất cả trong tất cả các bạn cần phải hiểu những gì sẽ xảy ra khi các loại biến khác nhau được so sánh với toán tử ==. Ngoài ra nó có lẽ là khôn ngoan để nhận ra rằng == gần như không bao giờ những gì bạn muốn và sử dụng === (mà sẽ không typecast giá trị của bạn) là ALOT an toàn hơn.

0

Mã có vẻ phát ra từ thử nghiệm đơn vị nhằm mục đích đánh bắt lỗi, do đó có sự so sánh có vẻ kỳ lạ. Trong cùng một ánh sáng, nó có thể được chuẩn bị để kiểm tra đơn vị chính để xác nhận rằng toán tử == hoạt động đúng - như nó cần.

Các vấn đề liên quan