Почему PHP считает, что 0 равно строке?

У меня есть следующий кусок кода:

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

Он предназначен для инициализации цены товара до 0, а затем получения информации об этом. Если цена указана как "е", это означает обмен вместо продажи, который хранится в базе данных как отрицательное число.

Также есть возможность оставить цену как 0, потому что товар является бонусом или потому что цена будет установлена позже.

Но всякий раз, когда цена не установлена, что оставляет ее с начальным значением 0, указанный выше цикл if оценивается как истина, и цена устанавливается на -1. То есть он считает 0 равным "е".

Как это можно объяснить?

Редактировать: когда цена указана как 0 (после инициализации), поведение ошибочно: иногда if оценивается как true, иногда - как false.

Ответ 1

вы делаете ==, который сортирует типы для вас.

0 - это int, поэтому в этом случае он будет отличать 'e' от int. Который не может быть разобран как один и станет 0. Строка '0e' станет 0 и будет соответствовать!

использовать ===

Ответ 2

Это связано с тем, как PHP выполняет операцию сравнения, которую оператор сравнения == обозначает:

Если вы сравниваете число со строкой или сравнение включает в себя числовые строки, каждая строка преобразуется в число и выполняется сравнение численно. [...] Преобразование типа не происходит, когда сравнение === или !==, поскольку это включает в себя сравнение типа, а также значения.

Поскольку первым операндом является число (0), а второе - строка ('e'), строка также преобразуется в число (см. также таблица Сравнение с различными типами). Страница руководства в строковом типе данных определяет, как выполняется строка для преобразования чисел:

Когда строка оценивается в числовом контексте, результирующее значение и тип определяются следующим образом.

Если строка не содержит символов ".", "e" или "e", а числовое значение соответствует ограничениям типа целочисленного типа (как определено PHP_INT_MAX), строка будет оцениваться как целое число. Во всех остальных случаях он будет оцениваться как float.

В этом случае строка 'e' и, следовательно, будет оцениваться как float:

Значение задается начальной частью строки. Если строка начинается с действительных числовых данных, это будет используемое значение. В противном случае значение будет 0 (ноль). Действительные числовые данные являются необязательным знаком, за которым следуют одна или несколько цифр (необязательно содержащие десятичную точку), за которыми следует необязательный показатель. Показатель - это "e" или "e", за которым следует одна или несколько цифр.

Поскольку 'e' не запускается с действительными числовыми данными, он вычисляет float 0.

Ответ 3

"ABC" == 0

оценивает true потому что сначала "ABC" преобразуется в целое число и становится 0 затем сравнивается с 0.

Это странное поведение языка PHP: обычно можно ожидать, что 0 будет переведен в строку "0" а затем сравнен с "ABC" с результатом false. Возможно, то, что происходит в других языках, таких как JavaScript, где слабое сравнение "ABC" == 0 оценивает как false.

Строгое сравнение решает проблему:

"ABC" === 0

оценивает false

Но что, если мне нужно сравнить числа в виде строк с числами?

"123" === 123

оценивает false потому что левый и правый члены имеют разные типы.

Что на самом деле нужно, так это слабое сравнение без ловушек в PHP-жонглировании.

Решение состоит в том, чтобы явным образом продвигать термины в строку, а затем проводить сравнение (строгий или слабый больше не имеет значения).

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

является

true

в то время как

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

является

false


Применительно к исходному коду:

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

Ответ 4

Оператор == будет пытаться сопоставить значения, даже если они имеют разные типы. Например:

'0' == 0 will be true

Если вам требуется сравнение типов, используйте оператор ===:

'0' === 0 will be false

Ответ 5

Ваша проблема - оператор с двойным равенством, который будет приписывать правый член типу слева. Используйте строгую, если хотите.

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

Вернемся к вашему коду (скопировано выше). В этом случае, в большинстве случаев, $item ['price'] является целым числом (кроме случаев, когда оно равно e, очевидно). Таким образом, по законам PHP, PHP будет выводить "e" на integer, что дает int(0). (Не верьте мне? <?php $i="e"; echo (int)$i; ?>).

Чтобы легко уйти от этого, используйте оператор тройного равенства (точного сравнения), который будет проверять тип и не будет подразумевать тип.

P.S: факт забавы PHP: a == b не означает, что b == a. Возьмите ваш пример и отмените его: if ("e" == $item['price']) никогда не будет выполняться при условии, что $item ['price'] всегда является целым числом.

Ответ 6

В PHP существует довольно удобный метод для проверки сочетания "0", "false", "off" как == false и "1", "on", "true" как == true, который часто игнорируется, Это особенно полезно для разбора аргументов GET/POST:

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

Это не относится к этому прецеденту, но с учетом сходства и факта это результат поиска, который пытается найти, когда задает вопрос о проверке (string) "0" как false. Я думал, что это поможет другим.

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

Ответ 7

Вы должны использовать === вместо ==, потому что обычный оператор не сравнивает типы. Вместо этого он попытается придать тип товарам.

Между тем === учитывает тип предметов.

  • === означает "равно",
  • == означает "eeeeh.. kinda выглядит"

Ответ 8

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

//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). 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 why its true)
echo ("bla" === "blaa"); //false because the values are not the same. The type is the same but === check 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 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)

//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)

Надеюсь, поможет.