Сравнение значений в PHP: оператор == (два равно)

Раздел: Условные конструкции и сравнение -> Операции сравнения

Оператор == (два знака равенства) в PHP выполняет сравнение значений с неявным приведением типов. Это означает, что перед непосредственным сравнением PHP преобразует оба операнда к общему типу, если они изначально различны. Такой подход удобен, но часто приводит к неожиданным результатам, если не учитывать правила приведения.

Основное использование оператора ==

Самый простой способ проверить равенство двух величин - записать $a == $b. PHP сравнивает значения после приведения типов. Например:

$a = '123';
$b = 123;
if ($a == $b) {
    echo 'Равны';
} else {
    echo 'Не равны';
}
// Вывод: Равны

Php два равно (оператор сравнения == в php)

Строка '123' преобразовалась в целое число 123, поэтому условие истинно. Это поведение определено в документации PHP и зависит от таблицы сравнения типов.

Типичная ошибка:

Сравнение строки, начинающейся с цифр, и числа:

$str = '123abc';
$num = 123;
var_dump($str == $num); // bool(true)

PHP преобразует '123abc' в число 123 (отбрасывая нечисловую часть), поэтому результат true. Это может скрыть ошибку, если ожидается строгое совпадение.

Как избежать неявного приведения типов при проверке равенства?

Для строго сравнения без приведения типов используется оператор === (три равно). Он проверяет не только значение, но и тип операндов.

$a = '123';
$b = 123;
var_dump($a === $b); // bool(false)

Рекомендуется использовать === везде, где не требуется приведение типов, особенно при проверке результата функции, которая может вернуть false или 0.

Проблема: оператор == считает 0 и false равными:

var_dump(0 == false); // bool(true)
var_dump('' == false); // bool(true)

Это одна из самых частых причин логических ошибок. Решение - использовать ===.

Как сравнить строки без учёта регистра, используя ==?

Оператор == учитывает регистр символов. Для сравнения без учёта регистра применяют функцию strcasecmp() или приводят строки к одному регистру перед сравнением.

$str1 = 'Hello';
$str2 = 'hello';
var_dump($str1 == $str2); // bool(false)

// Вариант 1: strcasecmp
if (strcasecmp($str1, $str2) === 0) {
    echo 'Равны без учёта регистра';
}

// Вариант 2: приведение к нижнему регистру
if (strtolower($str1) == strtolower($str2)) {
    echo 'Равны после приведения';
}

Функция strcasecmp() возвращает 0 при равенстве, что надёжнее, так как == после приведения может дать true даже для строк, которые после преобразования стали одинаковыми числового типа.

Как сравнить два объекта с помощью ==?

Оператор == для объектов сравнивает их как экземпляры одного и того же класса с одинаковыми значениями свойств (поверхностное сравнение). При этом объекты считаются равными, если они относятся к одному классу и все их свойства совпадают.

class User {
    public $name;
    public function __construct($name) {
        $this->name = $name;
    }
}

$obj1 = new User('Alice');
$obj2 = new User('Alice');
$obj3 = $obj1;

var_dump($obj1 == $obj2); // bool(true)
var_dump($obj1 === $obj2); // bool(false)
var_dump($obj1 === $obj3); // bool(true)

Для глубокого сравнения пользовательских объектов следует реализовать метод __toString() или использовать специальные функции.

Ошибка: сравнение объектов разных классов через == всегда возвращает false, даже если их свойства идентичны:

class A { public $val = 1; }
class B { public $val = 1; }
$a = new A;
$b = new B;
var_dump($a == $b); // bool(false)

Это ожидаемое поведение: разные классы считаются разными объектами.

Как сравнить массивы с помощью ==?

Для массивов оператор == сравнивает все пары ключ-значение после приведения типов значений. Массивы равны, если они содержат одинаковые пары (с учётом типов после приведения).

$arr1 = ['a' => 1, 'b' => '2'];
$arr2 = ['a' => '1', 'b' => 2];
var_dump($arr1 == $arr2); // bool(true)

$arr3 = ['a' => 1, 'b' => 2];
var_dump($arr1 == $arr3); // bool(false) - разные значения 'b'

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

Расширенные примеры использования оператора ==

Рассмотрим неочевидные и редко встречающиеся случаи сравнения с приведением типов.

Сравнение с ресурсами

Пример
$handle1 = fopen('/dev/null', 'r');
$handle2 = fopen('/dev/null', 'r');
var_dump($handle1 == $handle2); // bool(false) - разные идентификаторы ресурсов
fclose($handle1);
fclose($handle2);

Ресурсы считаются равными только если одна и та же ссылка (один и тот же идентификатор).

Сравнение с типом float и погрешности

Пример
$sum = 0.1 + 0.2;
var_dump($sum == 0.3); // bool(false)
var_dump($sum); // float(0.30000000000000004)
echo 'Причина: арифметика с плавающей точкой даёт погрешность.';
// Решение: сравнивать с эпсилоном или использовать round
var_dump(abs($sum - 0.3) < 1e-10); // bool(true)

Оператор == не выполняет округление, поэтому прямое сравнение десятичных дробей ненадёжно.

Сравнение null, false и пустой строки

Пример
var_dump(null == 0);        // bool(true)
var_dump(null == '');       // bool(true)
var_dump(null == false);    // bool(true)
var_dump(false == 0);       // bool(true)
var_dump(false == '');      // bool(true)
var_dump('0' == false);     // bool(true)
var_dump('0' == null);      // bool(false)

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

Сравнение строк, похожих на числа

Пример
var_dump('42' == 42);               // true
var_dump('42abc' == 42);            // true (как в примере выше)
var_dump('abc42' == 0);             // true (нечисловая строка преобразуется в 0)
var_dump('0x10' == 16);             // true (шестнадцатеричная строка)
var_dump('1e2' == 100);             // true (экспоненциальная запись)
var_dump(' 42' == 42);              // true (пробел игнорируется)
var_dump(' 42.0' == 42);            // true

Строки, начинающиеся с пробелов и содержащие числа, корректно преобразуются. Однако 'abc42' даёт 0, что часто становится сюрпризом.

Сравнение объектов, реализующих __toString

Пример
class StrClass {
    private $value;
    public function __construct($val) { $this->value = $val; }
    public function __toString() { return $this->value; }
}

$obj1 = new StrClass('100');
$obj2 = new StrClass(100);
var_dump($obj1 == $obj2); // bool(true) - после приведения через __toString оба становятся '100', затем в число 100
// Но объекты разных экземпляров? Всё равно true, так как класс один и поля равны после приведения.
echo 'Примечание: __toString не вызывается при сравнении объектов, объекты сравниваются через свойства. В данном случае свойство $value после приведения внутри == дало совпадение.';

Этот пример демонстрирует, что == для объектов сначала сравнивает класс и свойства, а если свойства сами являются объектами, то к ним тоже применяется рекурсивное сравнение.

Сравнение с использованием switch (неявно ==)

Пример
$val = '2abc';
switch ($val) {
    case 2:
        echo 'case 2 сработал';
        break;
    case '2abc':
        echo 'case 2abc сработал';
        break;
}
// Вывод: case 2 сработал
// Потому что в switch неявно выполняется == (с приведением типов)

Конструкция switch использует нестрогое сравнение (==), что может приводить к непредсказуемому выбору ветки. Для строгого сравнения следует применять match (PHP 8.0+).

Сравнение массивов с различной последовательностью ключей

Пример
$a = ['x' => 1, 'y' => 2];
$b = ['y' => 2, 'x' => 1];
var_dump($a == $b);  // bool(true) - порядок ключей не важен
var_dump($a === $b); // bool(false) - порядок ключей важен для строгого сравнения

Для == массивы равны, если содержат одинаковые пары, независимо от порядка ключей.

Сравнение с boolean

Пример
var_dump(true == 'true');   // bool(false) - 'true' не преобразуется в булево
var_dump(true == 1);        // bool(true)
var_dump(true == '1');      // bool(true)
var_dump(false == 'false'); // bool(false)
var_dump(false == 0);       // bool(true)

Строки, не являющиеся числами, преобразуются в 0 при сравнении с числом, но при сравнении с true они преобразуются в 1, только если строка равна '1' или числовое представление не 0.

Оператор сравнения == в PHP - comments

En
Php два равно (php)