== и === в PHP: разница, подводные камни и лучшие практики

== и === в PHP: разница, подводные камни и лучшие практики

== и === в PHP: разница, подводные камни и лучшие практики

Тема запроса: «PHP == и ===: в чём разница и когда что использовать». Если вы только начинаете или уже пишете на PHP, понимание сравнения — обязательный шаг к надёжному коду. Нестрогое сравнение (==) выполняет приведение типов «на лету», а строгое (===) сравнивает и значение, и тип без неявных преобразований. Ошибки в этой области ведут к багам и уязвимостям, особенно при проверках входных данных и паролей.

Коротко: отличие == и ===

  • == сравнивает значения с неявным приведением типов (loose comparison).
  • === сравнивает значения и типы, без приведения (strict comparison).
  • var_dump(42 == "42");    // true (строка приводится к числу)
    var_dump(42 === "42");   // false (разные типы: int vs string)
    

    Как работает нестрогое сравнение (==) в PHP

    При использовании == PHP старается «свести» операнды к общему типу. Главное помнить:

  • Число и строка → строка приводится к числу: «123abc» станет 123, «abc» станет 0.
  • Две строки → если обе «числовые строки», сравнение числовое; иначе — строковое.
  • Булево и что-то ещё → всё приводится к булеву: 0, «», «0», [] считаются false.
  • var_dump("" == 0);       // true (пустая строка → 0)
    var_dump("0" == false);   // true ("0" → false)
    var_dump("abc" == 0);     // true ("abc" → 0)
    var_dump("0123" == 123);  // true (числовое сравнение)
    

    Такая магия приводит к неожиданностям и даже уязвимостям. Поэтому по умолчанию предпочитайте ===.

    Опасный кейс: «магические» хеши и 0e…

    Классическая уязвимость при сравнении хешей с ==: некоторые MD5/sha1 значения начинаются с «0e…», что выглядит как число в экспоненциальной форме и при нестрогом сравнении превращается в 0.

    $storedHash = md5("240610708");   // "0e462097431906509019562988736854"
    $givenHash  = "0e123456789000000000000000000000"; // поддельное значение
    
    var_dump($storedHash == $givenHash);   // true (!) из-за численного сравнения 0 == 0
    var_dump($storedHash === $givenHash);  // false (строгое сравнение)
    
    // Как правильно сравнивать хеши
    if (hash_equals($storedHash, $givenHash)) {
        // безопасное, тайминг-устойчивое сравнение строк
    }
    

    Вывод: для сравнения секретов (токены, подписи, хеши паролей) используйте hash_equals и не применяйте ==.

    Списки и поиск: in_array, array_search и строгий флаг

    По умолчанию in_array и array_search сравнивают нестрого. Это может дать ложные совпадения.

    $list = [0, 1, 2];
    var_dump(in_array("0", $list));        // true ("0" == 0)
    var_dump(in_array("0", $list, true));   // false (строгое сравнение)
    
    var_dump(array_search(false, ["0", "1", "2"]));        // 0 (нашёлся "0")
    var_dump(array_search(false, ["0", "1", "2"], true));   // false (не найдено)
    

    Рекомендация: почти всегда передавайте третий аргумент true, чтобы включить строгое сравнение.

    switch в PHP тоже сравнивает нестрого

    Оператор switch использует == при сравнении со значениями case. Будьте осторожны со строками «0», пустыми строками и булевыми.

    $value = "0";
    switch ($value) {
        case false:  echo "false"; break;   // сработает (!), т.к. "0" == false
        case 0:      echo "zero"; break;
        case "0":   echo "string zero"; break;
    }
    // Выведет: false
    

    Решение: избегайте таких неоднозначностей в switch или приводите тип явно перед сравнением.

    Массивы: == против ===

    У массивов == проверяет равенство пар ключ=>значение без учёта порядка. === дополнительно учитывает порядок и типы.

    $a = ["x" => 1, "y" => 2];
    $b = ["y" => 2, "x" => 1];
    var_dump($a == $b);   // true
    var_dump($a === $b);  // false (другой порядок)
    

    Строковое vs числовое сравнение строк

    Если обе строки — числовые, сравнение будет числовым; иначе — лексикографическим.

    var_dump("2" < "10");    // false (числовое: 2 < 10 → true, но оба операнда строки? В PHP это всё равно числовое → true)
    var_dump("2" < "10");    // true на самом деле, т.к. обе — числовые строки
    var_dump("a2" < "10");   // false ("a2" не числовая — сравнение строковое)
    

    Чтобы избежать сюрпризов, приводите тип явно: (int) $s, (float) $s или валидируйте is_numeric($s).

    Сравнение float: не используйте ==

    Из-за двоичной природы float точные совпадения редки. Сравнивайте с допуском (epsilon).

    $a = 0.1 + 0.2; // 0.30000000000000004
    $b = 0.3;
    $eps = 1e-12;
    var_dump(abs($a - $b) < $eps); // true
    

    Полезные функции и приёмы

  • is_numeric, is_int, is_bool — проверяйте тип прежде чем сравнивать.
  • hash_equals — для сравнения секретов и хешей.
  • filter_var — валидируйте ввод перед приведением типов.
  • Тернарный оператор ?: и null coalescing ?? не заменяют строгое сравнение — будьте внимательны к «пустым» значениям.
  • $v = "0";
    var_dump(empty($v));     // true ("0" считается пустой)
    var_dump($v === "0");   // true — точная проверка на строку "0"
    

    Оператор «космический корабль»

    Удобен для сортировок: возвращает -1, 0 или 1, и учитывает приведение аналогично обычным сравнениям. Лучше явно приводить типы перед использованием.

    usort($rows, function ($a, $b) {
        return (int)$a['age']  (int)$b['age'];
    });
    

    Чек-лист лучших практик

  • По умолчанию используйте === и !==.
  • Всегда включайте строгий флаг в in_array/array_search: in_array($x, $arr, true).
  • Секреты сравнивайте через hash_equals, не через == или ===.
  • Перед сравнением чисел приводите строку к числу и валидируйте is_numeric.
  • Для float используйте сравнение с допуском.
  • Будьте осторожны со switch и «пустыми» значениями ("", "0", 0, false, null).
  • Для массивов учитывайте, что порядок влияет на ===, но не на ==.
  • Итоги

    Нестрогое сравнение в PHP удобно, но коварно. Используйте === как «дефолтный» инструмент, а к == обращайтесь только там, где вы на 100% контролируете типы и ожидаемое приведение. Это снижает количество скрытых багов и повышает безопасность вашего приложения.

    Хотите системно прокачать основы и научиться писать надёжный PHP‑код с базой данных и практикой? Посмотрите курс «PHP и MySQL с Нуля до Гуру 3.0 — практикум для уверенного старта».

    Источник

    НЕТ КОММЕНТАРИЕВ

    Оставить комментарий