Подтвердить что ты не робот

Почему декремент NULL не отрицателен в этом массиве?

Я пробовал этот код

$a = array_fill(0, 4, NULL);
$a[0]++;
++$a[1];
$a[2]--;
--$a[3];
var_dump($a);

Результат:

array(4) {
    [0]=> int(1)
    [1]=> int(1)
    [2]=> NULL
    [3]=> NULL
}

Почему значение индекса 2 и 3 не является отрицательным?

4b9b3361

Ответ 1

Используйте источник, Luke

Как обычно, ответ лежит в источнике. PHP выполняет следующие внутренние функции для выполнения операций инкремента и декремента:

ZEND_API int increment_function(zval *op1)

ZEND_API int decrement_function(zval *op1)

Эти операции изменяют аргумент op1 на основе его типа (NULL - тип); внутри increment_function() вы можете увидеть следующую ветку в коде:

case IS_NULL:
    ZVAL_LONG(op1, 1);
    break;

Приведенный выше код меняет тип op1 на число и устанавливает его значение в 1.

И наоборот, decrement_function() не предлагает такой ветки, и поэтому будет выполняться действие по умолчанию:

default:
    return FAILURE;

Запуск этого кода фактически не приведет к какой-либо наблюдаемой ошибке, потому что возвращаемые значения поглощаются в Zend VM, но переменная определенно не обновляется.

Это не ошибка (tm)

Вы можете быть удивлены, узнав, что это поведение, в том числе и для логических значений, на самом деле задокументировано:

Примечание. Операторы increment/decment не влияют на логические значения. Уменьшение значений NULL также не влияет, но приращение их приводит к 1.

Относительно булевых:

$a = true;
var_dump($a--); // true
$a = false;
var_dump($a++); // false

Относительно строк:

$letter = 'A';
var_dump(++$letter); // B
var_dump(--$letter); // B

Ответ 2

Странно, но задокументировано на странице php doc с добавочными/сокращающими операциями:

Примечание. Операторы increment/decment не влияют на логические значения. Уменьшение значений NULL также не влияет, но приращение их приводит к 1.

Ответ 3

Странно. Я не знаю их решающего фактора для этого, но, глядя на исходный код, вы увидите, что если он имеет дело с NULL, он устанавливает он равен 1 (не приращение).

case IS_NULL:
    ZVAL_LONG(op1, 1);
    break;

Функция декремент не имеет отношения к NULL вообще и идет прямо в FAILURE:

default:
    return FAILURE;

Как уже упоминалось, это документально.

Примечание. Операторы increment/decment не влияют на логические значения. Уменьшение значений NULL также не влияет, но приращение их приводит к 1.