Arrays

foreach

One of the most commonly used ways to iterate over an array in PHP is using the foreach statement. Up to version 7, however, the behavior of foreach has been a bit unexpected in some edge cases. This has changed in PHP 7:

We would not expect your code to rely on PHP’s behavior in any of the above edge cases, but if it does, then you need to adjust the code before migrating to PHP 7.

Let us look at some examples:

$array = [0, 1, 2];
foreach ($array as &$value) {
    var_dump(current($array));
}

Executed with PHP 5, the above code would output:

int(1)
int(2)
bool(false)

Executed with PHP 7, the output will be:

int(0)
int(0)
int(0)

As you can see, foreach no longer changes the internal array pointer in PHP 7.

When iterating by-reference, foreach will now do a better job of tracking changes to the array made during iteration. For example, appending to an array while iterating will now result in the appended values being iterated over as well:

$array = [0];
foreach ($array as &$val) {
    var_dump($val);
    $array[1] = 1;
}

This example, executed with PHP 5, would output:

int(0)

PHP 7, will iterate over both values:

int(0)
int(1)

When you do not use the reference operator &, PHP will operate on a copy of the array, so any changes made to the (original) array will not affect the values that are iterated.

When iterating over a non-traversable object, the behavior will be the same as when iterating array by reference. This means that properties that are added while iterating will also be iterated over. When properties that have not yet been iterated over are removed, they will not be iterated over anymore.

Invalid list() Usage

The list() function can be used to easily dereference various elements of an array into individual variables. To make this feature more robust, various use cases got removed. Starting with PHP 7, the following examples are all invalid and do no longer work:

list() = [1,2,3];
list(,,) = [1,2,3];
list($a, list(), $b) = [1,2,3];

Support for unpacking strings using list also got removed:

list($a, $b) = "ab";

Executing the above sample will now result in $a and $b to be null, rather than ‘a’ and ‘b’.

Parsing Invalid Octal Numbers

Integer values can be specified in various representations, for instance in hexadecimal or octal form. The later are detected by PHP based on their leading zero:

$int = 0123;

var_dump($int);

var_dump() will not output 123 but the correct integer value 83.

As the octal system only knows the digits 0 through 7, the following is not a valid octal representation of an integer value:

$invalid = 0191;
var_dump($invalid);

Previous versions of PHP silently discarded the invalid digit and all that follow regardless whether they were valid or not. Given the example above this behavior lead to an incorrect result:

int(1)

Starting with PHP 7, invalid octal literals now produce compile-time errors, thus the above example would no longer work:

PHP Parse error:  Invalid numeric literal in ...

Changed Order for list() when Assigning to Array

PHP’s list() function can be used to conveniently unpack array elements into single variables:

list($a, $b, $c) = [1, 2, 3];

var_dump($a);
var_dump($b);
var_dump($c);

Executing the code shown above will print the output shown below:

int(1)
int(2)
int(3)

Unbeknownst to most PHP developers, before PHP 7 the assignments were done in reverse order, assigning the last value to the last variable in the list first. This could lead to unexpected behavior when new array elements are used as target variables:

list($array[], $array[], $array[]) = [1, 2, 3];

var_dump($array);

Executed with PHP 5, the output was:

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

As can be seen, due to the reverse order of the assignment using list() the order of values within the array is effectively reversed as well.

PHP 7 changed the order of assignment to be starting on the left, resulting in a backwards compatibility break for this use case. Consequently, when run with PHP 7, the output now looks like this:

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

If you want to be on the safe side, you might want to use array_reverse() to fix the element order.

[] Operator and Empty Strings

Prior to PHP 7.1, a variable that holds an empty string was silently converted to an empty array when the [] operator was used on it:

$string   = '';
$string[] = 'foo';
var_dump($string);

Executing the code shown above with PHP 5.6 or PHP 7.0 prints the following output:

array(1) {
  [0]=>
  string(3) "foo"
}

PHP 7.1 and later print the error message shown below for the same code:

Fatal error:
Uncaught Error: [] operator not supported for strings

Using the [] operator on non-empty strings results in an error since PHP 5.6.

Invalid Array Read Access

Elements of an array are accessed using square bracket notation: $foo[0]. The same syntax works for variables of type string to access a specific char and objects that implement ArrayAccess. Surprisingly though, PHP did not have any issues with trying to apply the same access logic on values of type int, bool, float or even null. As this does not make sense, PHP simply returned null.

PHP 7.4 will now emit an E_NOTICE error for these invalid read accesses. While this change does not seem to qualify as a break of backward compatibility in itself, it may have breaking side effects in case a custom, userland error handler is in place: these are often implemented to unconditionally translate errors into exceptions and with that change the behavior of the code.

compact()

One of the more “interesting” functions in PHP is compact(). It creates an array from variable names that are specified as strings. Clearly, compact() dates back to the dark times when register_global ruled PHP world, and should be used very rarely these days.

$a = 1;
$b = 2;

var_dump(compact('a', 'b'));

This will give you an array of $a and $b, with the variable names as keys:

array(2) {
  ["a"] => int(1)
  ["b"] => int(2)
}

Up to PHP 7.3, referencing undefined variables would be silently ignored by PHP. As of PHP 7.3, a notice will be emitted:

var_dump(compact('a'));
PHP Notice:
compact(): Undefined variable: a in ...
array(0) {
}