Подтвердить что ты не робот

Очень нелогичные сравнения значений php

Я наткнулся на очень странный бит PHP-кода. Может ли кто-нибудь объяснить, почему это происходит? ***** BONUS POINTS *****, если вы можете сказать, почему это полезно.

<?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>";
}
?>

И получившийся результат:

48 should NEVER equal 97
false==0
4b9b3361

Ответ 1

В PHP "a" не является символом ASCII a, а строкой a. В числовом контексте оно равно 0. Например, intval('a') приводит к значению 0.

Это полезно, потому что PHP в основном используется для обработки текста, и, возможно, вы захотите попробовать тест (123 == '123'), который является истинным. И учитывая, что число в одиночных (или двойных) кавычках рассматривается как число, это не имеет смысла для строки без числового значения, которое должно рассматриваться как что-либо, кроме 0.

О да, еще одна вещь. "a" в булевом контексте является истинным, а не ложным. Я считаю, что это делает некоторые типы обработки текста более естественными, но я, честно говоря, не могу придумать пример в этот поздний час.

Ответ 3

Это основной принцип слабо/динамически типизированных языков, называемый тип жонглирования. В определенных обстоятельствах типы будут передаваться другим типам. Когда вы сравниваете строку с номером, строка будет передана в число. При сравнении чего-либо с логическим значением это значение будет передано в логическое значение.

Там правила для каждый type относительно того, как он будет преобразован в другой тип или как он сравнивает с другими типами. 'a' преобразуется в 0 при нажатии на число (единственный логический выбор, действительно). Чтобы избежать такого типа литья, проверьте не с оператором равенства ==, а с оператором идентификации Джеймс указал на, это полезно, поскольку PHP очень много работает со строками, которые действительно являются числами. Например, HTML-формы представляют только строки, даже если это число. Он также позволяет использовать некоторые действительно краткий код, например:

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

Это также означает, что вы должны быть очень осторожны в том, что нужно проверить, в каких обстоятельствах, хотя значение может неожиданно привести к чему-то другому. И, по общему признанию, 'a' == 0 сам по себе действительно является ловушкой типа жонглирования, а не полезной. Это одна из ситуаций, когда вы должны быть осторожны и испытывать, как if (is_numeric($var) && $var == 0).

Ответ 4

ord() принимает символы, поэтому PHP превращает 0 в '0'. И 0 равно false, хотя он не идентичен (===).

Ответ 5

Ознакомьтесь с PHP введите таблицы сравнения из руководства. Это очень удобная вещь, чтобы иметь под рукой, пока вы ее не усвоили, и было бесценным для моего понимания того, что будет оцениваться как истинное и когда.

Другие уже ответили на суть вопроса, но я думаю, что важно указать, что в PHP единственная непустая строка, которая не оценивает значение "true" с оператором ==, равна "0", поскольку PHP обрабатывает любая строка, содержащая только числа в виде целого числа или float.

Обоснованием для этого является то, что PHP довольно слабо набирается и пытается разрешить взаимозаменяемость целых чисел, строк, float и логических значений. Реальный и чрезвычайно распространенный пример этого - если вы используете функции mysql или PDO, строки возвращаются для всего, даже если базовый столбец является целым числом.

Рассмотрим следующий sql:

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');

И следующий код:

<?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";
    }
}

"Поле x не было строкой!" сообщение никогда не печатается, хотя каждый столбец в базе данных является целым числом. Предположим, вы хотите использовать вторую строку в этой таблице.

<?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!";
}

Если строка "0" не рассматривалась как целое число 0 для сравнения, вышеуказанный код никогда не будет печатать "Это было ноль!". Программист должен будет взять на себя ответственность за жонглирование типа значения, которое выходит из базы данных. Это нежелательно для слабо типизированного языка.

Строгое равенство, включая тип, проверяется с помощью оператора "Действительно, действительно, честного с богом, равным", который представлен символом "===".

Ответ 6

Я не вижу, как ('a' == 0) полезно

$var = '123abc';

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

Это сводится к неявным правилам преобразования PHP.

Я не думаю о практическом примере, но это основная причина, по которой вы видите это поведение.

расширения:

В вашем примере для сравнения используется 'a' для преобразования 0 (ноль). Представьте, что для целей сравнения это эквивалентно '0a'. (Что цифра нуль, а не буква "o." )

Дальнейшее расширение:

Я думал, что в руководстве был хороший пример использования, но я не смог его найти. То, что я встретил, должно помочь пролить свет на эту "нелогичную" ситуацию.

PHP - это прежде всего веб-сайт языка, а не общего назначения скриптовый язык. Поскольку Интернет не набирается, и все это строка, Мне нужно было сделать что-то немного по-разному на раннем этапе, чтобы сделать PHP что ожидали люди. В частности, "123" == 123 должно быть истинным, чтобы не нужно набирать листы каждый числовой пользовательский ввод.

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

Это точно не отвечает на вопрос, но указывает на общее направление.

Ответ 7

PHP - это свободно типизированный язык и позволяет сравнивать значения разных типов без ошибок, что делает его очень простым в использовании, но, как вы нашли, может вызвать некоторые странные, но логические выходы.

Ваш первый пример:

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

Когда сравниваются два разных типа значений, одно значение сначала преобразуется в тот же тип, что и другой, через литой, а затем сравнивается. В примере Int и String строка преобразуется в Int. Когда PHP превращает букву в строку, она принимает все первые числовые символы, а затем отбивные остальных: т.е. "123123afraa" становится 123123, "9a9" равно 9. Если строка не начинается с цифр, ей присваивается значение 0.

Поэтому ваш пример действительно: 0 === (string) 'a', который действительно 0 === 0, так как 'a' не начинается с числового. Я думаю, вы ожидали, что PHP вернет значение "a" в ASCII, которого нет! Это действительно полезно для дезинфекции строк, php редко требует рассмотрения значений ascii, для этого это слишком высокий уровень. (Для создания сайтов!)

Когда строка сравнивается с логическим значением, значение '' или '0' ложно, все остальные значения являются истинными. Это полезно, поэтому вы можете проверить, является ли значение "пустым":

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

if ($ _GET ['foo']))  {     // сделай что-нибудь  }

Когда целое число сравнивается с логическим значением, значение 0 равно false, другие значения истинны, это довольно стандартно.

Итак, в целом вам нужно понять, что происходит, когда разные типы переменных сравниваются с оператором ==. Также, вероятно, разумно понять, что == почти никогда не то, что вы хотите, и использование === (которое не будет выводить ваши значения) более безопасно.

Ответ 8

Код, по-видимому, исходит от unit test с целью обнаружения сбоев, следовательно, казалось бы, странных сравнений. В этом же свете может быть подготовлен к основному unit test, чтобы подтвердить, что оператор == работает правильно - как и должно быть.