Почему var_dump('0xafebac' == '11529132'); равно TRUE? Как происходит сравнение этих двух строк?
Это довольно длинная история.
РНР - язык со свободной типизацией. В нем можно спокойно сравнивать переменные любых типов, использовать их в различных выражениях и операторах. Например, для РНР нет проблемы вычислить. сколько будет 2 * '2' - он просто приведёт оба операнда к числовому типу, и выполнит операцию умножения.
Но за такую легкость приходится платить. В частности, РНР должен догадаться, что в переменной содержится число, даже если она имеет тип "строка". Почему так? А потому, что в большинстве случаев все переменные, попадающие в РНР извне, имеют тип "строка". Например, это все переменные, попадающие в скрипт по протоколу НТТР. Или переменные, попадающие в скрипт из базы данных через устаревшие протоколы.
И если мы хотим сравнить переменную, полученную из формы с переменной, полученной из БД, то нам в обязательном порядке надо попытаться привести их к числам, а иначе у нас будет '9' больше чем '100'. Вот РНР и пытается "догадаться" - является ли переменная числом, и если да - то приводит её к числовому типу.
Чтобы этого не происходило, надо сравнивать строки либо оператором строгого сравнения, ===, либо функцией strcmp().
При этом выражение вида '0xafebac' == '11529132' является частным случаем, который был
исправлен в версии 7.0: начиная с этой версии, строки, которые выглядят, как шестнадцатеричные, перестали распознаваться, как числовые.
Но при этом строки, которые выглядят, как число с экспонентой (например '1e3') всё еще распознаются как числа и поба операнда приводятся к числу. Поэтому '1e3' == 1000 будет true
Потому что в php при сравнении приводит обе строки к числу. Даже если оба операнда это строки. По факту это баг. В версиях выше 5.6 поведение стало более предсказуемым:
При нестрогом сравнении строки с числом, строка преобразуется к числу по описанным в документации правилам. А так как '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
Потому что сравнения для строк через == не реализовано. PHP видит что строки содержат числа и приводит их числу перед проверкой.
Для сравнения строк лучше использовать strcmp так её поведение не зависит от типа данных.
Как развивать веб-проекты в 2026 году: технологии, контент E-E-A-T и факторы доверия
Современные инструменты для криптотрейдинга: как технологии помогают принимать решения
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники