PHP Multidimensional Arrays

Chapter 28 7 mins

Learning outcomes:

  1. What are multidimensional arrays
  2. PHP's idea of arrays of arrays
  3. Handful of examples
  4. Modifying elements in 2D array via foreach

What are multidimensional arrays?

Have you ever encountered matrices in those old days at school in your mathematics classes? A matrix is essentially a two-dimensional structure to hold numbers that we could process in a multitude of ways.

In programming, when it became apparent that supporting matrices was paramount in code, the idea of two-dimensional, or 2D, arrays sprung up.

A 2D array is simply an array of elements, which in the case of a matrix are usually numbers, where accessing an element typically requires two indexing operations.

Similarly, a 3D array is an array where we typically need to access 3 indices before reaching a given end value.

In general,

An n-dimensional, or multidimensional, array is an array where we need to perform n indexing operations before reaching an end value.

Languages such as C and C++ truly support multidimensional arrays out of the box.

While defining an array in these languages, we get to further define its number of dimensions upfront. Thereafter, the compiler itself normalizes every sequence of indexing operations to one single indexing operation based on simple arithmetic.

Coming back to the topic, many modern-day dynamic languages — the likes of JavaScript, Python, and even PHP — don't, however, support true multidimensional arrays. They instead support another similar idea that could be used to emulate multidimensional arrays. That idea is of jagged arrays.

A jagged array, also known as an array of arrays, is an array whose each and every element is also an array.

As you can see, a jagged array is NOT a flat array consisting of scalar values as is the case with a multidimensional array. But thanks to this idea of nested arrays in a jagged array, we can try to replicate multidimensional arrays using it.

An indexing operation on a jagged array takes us to one of its constituent arrays, then another indexing operation takes us to one of that array's constituent arrays, and so on until we reach a final value.

Reiterating the fact about PHP, it does NOT support true multidimensional arrays.

But since an element of an array in PHP could be any valid value, when that value is an array itself, we have a jagged array, i.e. an emulation of a multidimensional array — specifically of a 2D array.

Let's now create some multidimensional arrays in PHP.

In the following discussion, we'll stick to just 2D arrays. The reason we abstain from creating 3D arrays and beyond is because they can quickly become overly complex to handle and are generally used to work with complex concepts.

Representing matrices

Consider the following 2 x 2 matrix of integers:

::\begin{bmatrix} 1 & 10 \\ 3 & 7 \end{bmatrix}::

Our goal is to represent it in PHP using an array and then perform the scalar multiplication matrix operation on it.

So first, let's get to the representation. Since a 2D array in PHP is just an array of arrays, there isn't anything new to learn syntactically — just initialize an array with arrays themselves.

<?php

$matrix = [
   // Code to go here.
];

The matrix above has two rows and so we'll need two elements in our $matrix array. Next, each of these arrays need to have two elements as well because that's the number of columns of the matrix. Altogether, we get to the following code:

<?php

$matrix = [
   [1, 10],
   [3, 7]
];

Simple.

With the representation done, now we need to perform the given scalar multiplication operation. Fortunately, it's superbly easy — just multiply each element by the given value.

For example, the scalar multiple of the 2x2 matrix above for the number 2, would be as follows.

::\begin{bmatrix} 2 & 20 \\ 6 & 14 \end{bmatrix}::

Given that we want to modify the original $matrix array, we'll use a basic set of nested for loops with the counter variables $i and $j, respectively.

Something like this:

<?php

$matrix = [
   [1, 10],
   [3, 7]
];

for ($i = 0, $len = count($matrix); $i < $len; $i++) {
   for ($j = 0; $j < $len; $j++) {
      $matrix[$i][$j] *= 2;
   }
}

Time to test whether our loop works as expected:

<?php

$matrix = [
   [1, 10],
   [3, 7]
];

for ($i = 0, $len = count($matrix); $i < $len; $i++) {
   for ($j = 0; $j < $len; $j++) {
      $matrix[$i][$j] *= 2;
   }
}

print_r($matrix);
Array ( [0] => Array ( [0] => 2 [1] => 20 ) [1] => Array ( [0] => 6 [1] => 14 ) )

And it indeed does.

We can even use foreach here but we'll do that later in this chapter owing to the fact that it requires usage of references in both the loops.

Iteration over 2D array using foreach

We learnt about the foreach loop in detail in the PHP Control Flow — foreach chapter. It's used to provide us with a much simpler way to iterate over a given array.

Using foreach, it's obviously possible to iterate over a multidimensional array, but we need to be careful when doing so if we are trying to make modifications to the underlying array.

Let's see what this means.

Given the following $matrix array:

<?php

$matrix = [
   [1, 10],
   [3, 7],
];

here's how we could iterate over it and print each row, by iterating over each number therein:

<?php

$matrix = [
   [1, 10],
   [3, 7],
];

foreach ($matrix as $row) {
   foreach ($row as $num) {
      echo "$num ";
   }
   echo "\n";
}
1 10 3 7

Nothing complicated at all.

But now let's say we want to perform the same scalar multiplication operation that we did before, albeit switch to using foreach instead.

Let's do it:

<?php

$matrix = [
   [1, 10],
   [3, 7],
];

// Perform scalar multiplication using foreach.
foreach ($matrix as $row) {
   foreach ($row as &$num) {
      $num *= 2;
   }
}

print_r($matrix);
Array ( [0] => Array ( [0] => 1 [1] => 10 ) [1] => Array ( [0] => 3 [1] => 7 ) )

What? The output doesn't seem to confirm that scalar multiplication has been performed.

Have we made $num a reference variable, since we need its modification to trigger the modification of the corresponding array element? Yes, we have made it one. Then what?

What could possibly be wrong here? Think about it.

Well, we've already discussed such a similar problem in the PHP Control Flow — foreach chapter. The problem is caused by the fact that at every stage of the outer foreach, the loop's variable $row that gets assigned the next item (which is an array) of $matrix receives a copy of that item.

So in the code above, each $row does NOT actually refer to the corresponding array in $matrix representing that row; instead, it refers to a copy of that row.

How to solve this problem? Simple — use references.

Let's modify the code above by labelling $row to be a reference variable. In this way, it'll receive the actual underlying array in each iteration of the loop.

Altogether, we get to the following code:

<?php

$matrix = [
   [1, 10],
   [3, 7],
];

// Perform scalar multiplication using foreach.
foreach ($matrix as &$row) { foreach ($row as &$num) { $num *= 2; } } print_r($matrix);
Array ( [0] => Array ( [0] => 2 [1] => 20 ) [1] => Array ( [0] => 6 [1] => 14 ) )

Perfect! We are all good now.