Оператор == для сравнения строк

130
26 июля 2019, 15:00

Почему var_dump('0xafebac' == '11529132'); равно TRUE? Как происходит сравнение этих двух строк?

Answer 1

Это довольно длинная история.

РНР - язык со свободной типизацией. В нем можно спокойно сравнивать переменные любых типов, использовать их в различных выражениях и операторах. Например, для РНР нет проблемы вычислить. сколько будет 2 * '2' - он просто приведёт оба операнда к числовому типу, и выполнит операцию умножения.

Но за такую легкость приходится платить. В частности, РНР должен догадаться, что в переменной содержится число, даже если она имеет тип "строка". Почему так? А потому, что в большинстве случаев все переменные, попадающие в РНР извне, имеют тип "строка". Например, это все переменные, попадающие в скрипт по протоколу НТТР. Или переменные, попадающие в скрипт из базы данных через устаревшие протоколы.

И если мы хотим сравнить переменную, полученную из формы с переменной, полученной из БД, то нам в обязательном порядке надо попытаться привести их к числам, а иначе у нас будет '9' больше чем '100'. Вот РНР и пытается "догадаться" - является ли переменная числом, и если да - то приводит её к числовому типу.

Чтобы этого не происходило, надо сравнивать строки либо оператором строгого сравнения, ===, либо функцией strcmp().

При этом выражение вида '0xafebac' == '11529132' является частным случаем, который был исправлен в версии 7.0: начиная с этой версии, строки, которые выглядят, как шестнадцатеричные, перестали распознаваться, как числовые.

Но при этом строки, которые выглядят, как число с экспонентой (например '1e3') всё еще распознаются как числа и поба операнда приводятся к числу. Поэтому '1e3' == 1000 будет true

Answer 2

Потому что в php при сравнении приводит обе строки к числу. Даже если оба операнда это строки. По факту это баг. В версиях выше 5.6 поведение стало более предсказуемым:

Answer 3

При нестрогом сравнении строки с числом, строка преобразуется к числу по описанным в документации правилам. А так как 'text' - это не числовая строка, то она преобразуется к 0.

Вот так устроено нестрогое сравнение в PHP.

ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) /* {{{ */
...
    while (1) {
    switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
        case TYPE_PAIR(IS_LONG, IS_LONG): ...
        case TYPE_PAIR(IS_DOUBLE, IS_LONG): ...
        case TYPE_PAIR(IS_LONG, IS_DOUBLE): ...
        case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE): ...
        case TYPE_PAIR(IS_ARRAY, IS_ARRAY): ...
        case TYPE_PAIR(IS_NULL, IS_NULL):
        case TYPE_PAIR(IS_NULL, IS_FALSE):
        case TYPE_PAIR(IS_FALSE, IS_NULL):
        case TYPE_PAIR(IS_FALSE, IS_FALSE):
        case TYPE_PAIR(IS_TRUE, IS_TRUE):
             ...
        case TYPE_PAIR(IS_NULL, IS_TRUE): ...
        case TYPE_PAIR(IS_TRUE, IS_NULL): ...
        case TYPE_PAIR(IS_STRING, IS_STRING): ...
        case TYPE_PAIR(IS_NULL, IS_STRING): ...
        case TYPE_PAIR(IS_STRING, IS_NULL): ...
        case TYPE_PAIR(IS_OBJECT, IS_NULL): ...
        case TYPE_PAIR(IS_NULL, IS_OBJECT): ...
        default:
             ...
            if (Z_TYPE_P(op2) == IS_OBJECT) {
             ...
            if (!converted) {
             ...
                } else {
                    op1 = zendi_convert_scalar_to_number(op1, &op1_copy, result, 1);
                    op2 = zendi_convert_scalar_to_number(op2, &op2_copy, result, 1);
            ...
                    converted = 1;
                }
            ...

Если не найдена необходимая пара типов, то оба операнда преобразуются к числу и идут на следующую итерацию while

Собственно из-за приведения типов при нестрогом сравнении и получаются вот такие паззлеры:

'text' == 0;  // true
false == 0;  //true
'text' == false;  // Внезапно false
Answer 4

Потому что сравнения для строк через == не реализовано. PHP видит что строки содержат числа и приводит их числу перед проверкой.

Для сравнения строк лучше использовать strcmp так её поведение не зависит от типа данных.

READ ALSO
Замена lcg_value() на rand

Замена lcg_value() на rand

Проверив код программы увидел, что lcg_value() генерирует такие точки, что укладывает их по сути все рядомЗначение сильно не меняется

110
Почему file_put_contents записывает не все содержимое?

Почему file_put_contents записывает не все содержимое?

Подскажите, почему file_put_contents в моем коде ниже, записывает не все содержимое, как исправить?

153
Как менять стиль в зависимости от выводимой даты?

Как менять стиль в зависимости от выводимой даты?

Только начал изучать php вопрос может прозвучать не совсем корректно для более опытных

106
Несколько изображений в одном товаре в каталоге

Несколько изображений в одном товаре в каталоге

Как реализовать галерею изображений одного товара в каталоге? Нужна реализация на php mysqlНе могу найти решение подобного вопроса

149