Почему 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 равным «e».

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

Изменить: когда цена указана как 0 (после инициализации), поведение неустойчиво: иногда значение if оценивается как true, иногда оно оценивается как false.

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

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

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

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

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

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

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

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

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

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

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

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

 '0' == 0 will be true 

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

 '0' === 0 will be false 

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

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

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

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

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

В 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

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