PHP 8.0: Implicit negative array key increments do not skip negative numbers

Version8.0
TypeChange

PHP 8.0 changes how it increments negative numeric array keys.

Prior to PHP 8.0, if an array has its last key as a negative number (such as -42), an array increment operation skipped all negative numbers and selected the next key as 0 or the next positive number. In PHP 8.0, this behavior is dropped, and array keys will be incremented regardless of the sign of the last key number.

$array = [
    -42 => 'Foo',
];
$array[] = 'Bar';

Prior to PHP 8.0, the array is incremented to key 0, because the last key is a negative number.

array(2) {
    [-42]=> string(3) "Foo" 
    [0]=> string(3) "Bar" 
}

In PHP 8.0 and later, this special negative array key treatment is removed, and array keys are incremented by adding 1, regardless of the sign.

array(2) {
    [-42]=> string(3) "Foo" 
    [-41]=> string(3) "Bar" 
}

This change was planned since PHP 7.3, and was expected to change in PHP 8.0. However, PHP did not emit any deprecation notices or warnings when it encounters such array increments.

All array increment operations are affected. This includes the array_fill and array_push functions.

array_fill

In PHP 8.0 and later, array_fill function behaves similar to the standard array incremental pattern; that it does not skip negative numbers.

$array = array_fill (-42, 3 , 'Value');
var_dump($array);

PHP 8.0 and later:

array(3) {
    [-42]=> string(5) "Value"
    [-41]=> string(5) "Value"
    [-40]=> string(5) "Value"
}

Prior to PHP 8.0, array_fill function skipped all negative numbers and started from 0:

array(3) {
    [-42]=> string(5) "Value"
    [0]=> string(5) "Value"
    [1]=> string(5) "Value"
}

array_push

Similar to array_fill, array_push function also determines the next array key without skipping negative numbers.

$array = [
    -42 => 'Foo',
];

array_push($array, "Bar");
var_dump($array);

PHP 8.0 and later:

array(2) {
    [-42]=> string(3) "Foo"
    [-41]=> string(3) "Bar"
}

Prior to PHP 8.0, the next key as determined by array_push skipped negative numbers to 0 or next positive integer:

array(2) {
    [-42]=> string(3) "Foo"
    [0]=> string(3) "Bar"
}

Backwards Compatibility Impact

This change breaks backwards-compatibility, and might result in subtle bugs that are not easily detected. However, this change will likely be a harmless change because all array values will be stored regardless of the key value.

Note that in all versions, PHP automatically coerces numeric strings (such as "42") to an int (such as 42) when used as an array key. This happens even if strict types is enabled (declare(strict_types=1)). It is possible that arrays are initiated with negative numbers without realizing it, and with PHP 8.0, direct access to said arrays (such echo $array[0]) can result in unexpected behavior.

Code that relied on PHP's behavior of skipping to 0 will not work as intended in PHP 8.0.


RFC Discussion Implementation