Arrays are a very common construct of the average PHP project. And when we have arrays, we are going to need some way to manipulate and transform them into something we can work with. In this article I will provide a few examples of the array functions I use most often.
The User class
Some of the examples in this article will use a “User” class. For reference, I’ve included it here:
<?php class User { private $id; private $name; private $email; private $score; public function __construct( string $id, string $name, string $email, int $score = 0 ) { $this->id = $id; $this->name = $name; $this->email = $email; $this->score = $score; } public function get_id(): string { return $this->id; } public function get_name(): string { return $this->name; } public function get_email(): string { return $this->email; } public function get_score(): int { return $this->score; } }
This class is as basic as they come. It doesn't do anything interesting on its own, but it will come in handy for some demonstrations later on.
array_map()
The array_map function loops over all of the array's elements and executes a callback function for each of them. When it is done, it returns an array of the same length. The contents of the returned array are determined by the callback function’s return statement.
Squaring an array of integers
We can apply an array_map to generate an array which contains the square of each the input array’s integer elements:
<?php $input_array = array( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ); $squared = array_map( function ( $n ) { return $n ** 2; }, $input_array );
Array of objects
The input array can consist of any variable type, such as objects. This is where type-hinting becomes useful:
<?php $users = array( new User( '1000', 'name1', 'email1@example.com' ), new User( '1001', 'name2', 'email2@example.com' ), new User( '1002', 'name3', 'email3@example.com' ), new User( '1003', 'name4', 'email4@example.com' ), new User( '1004', 'name5', 'email5@example.com' ), ); $email_addresses = array_map( function ( User $user ) { return $user->get_email(); }, $users );
In this example we generate an array of email addresses from the users array. My IDE can help me remember what methods and properties are available for the User objects while I’m writing the callback function body.
Multiple input arrays
The array_map function offers support for multiple input arrays at the same time. This can be useful when we want access to both the array keys and values in the callback function.
<?php $colors = array( 'red' => '#FF0000', 'green' => '#00FF00', 'blue' => '#0000FF', ); $result = array_map( function ( string $name, string $hex ) { return $hex . ' looks like ' . $name; }, array_keys( $colors ), array_values( $colors ) );
array_filter()
The array_filter function can return a subset of the input as a new array. Just like the array_map function, one of its arguments is a callback function. In the case of array_filter, the callback function should return a boolean value to indicate whether or not the current element should be included in the subset.
In contrast with array_map, the first argument should be the input array, and the second argument should be the callback function. Only one input array is permitted for the array_filter function.
Filtering odd integers
To get only the odd numbers from an array of integers, we can use the modulo operator in the array_filter function’s callback:
<?php $input_array = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; $odd_numbers = array_filter( $input_array, function ( int $n ) { return $n % 2 !== 0; } );
Filtering an array of objects
When working with an array of objects, the callback function arguments can be type-hinted, just like with the array_map function. In the following example, we can retrieve only the users whose score is greater than 50.
<?php $users = array( new User( '1000', 'name1', 'email1@example.com', 95 ), new User( '1001', 'name2', 'email2@example.com', 30 ), new User( '1002', 'name3', 'email3@example.com', 71 ), new User( '1003', 'name4', 'email4@example.com', 20 ), new User( '1004', 'name5', 'email5@example.com', 50 ), ); $users = array_filter( $users, function ( User $user ) { return $user->get_score() > 50; } );
list()
The list function can be used to assign a variable to some or all of an array’s elements.
A simple example
Let’s start small. In the following example, $arg1 will equal “red”, $arg2 will equal “green”, and $arg3 will equal “blue. Pretty easy, right?
<?php $args = array('red', 'green', 'blue'); list($arg1, $arg2, $arg3) = $args;
With array keys
What if the input array has non-numeric array keys? The list function doesn’t seem to work anymore. Each variable generated by the list function will have a value of NULL:
<?php $args = array( 'red' => '#FF0000', 'green' => '#00FF00', 'blue' => '#0000FF', ); list($arg1, $arg2, $arg3) = $args;
When we know the input array’s array keys, we can just use them in the list function:
<?php $args = array( 'red' => '#FF0000', 'green' => '#00FF00', 'blue' => '#0000FF', ); list(‘red’ => $arg1, ‘green’ => $arg2, ‘blue’ => $arg3) = $args;
array_reduce()
The array_map function returns an array of the same length, and array_filter returns a subset of the original array. But the return value of the array_reduce function is a wildcard. It can distill an array of data into a single boolean or integer value, or it could return a complex nested array, or even an object of a custom class. This is what makes array_reduce so powerful, and my favourite of all the array functions.
This function takes 3 arguments. The first argument is the input array. The second argument is the callback function. And the last argument is an initial value.
The callback function loops over all elements in the input array, and takes 2 arguments. The first will be the “carry”, and the second will be the current array element. This “carry” starts as the same value as the third “initial value” parameter of the array_reduce function, and will be updated every loop by the return statement of the callback function.
Returning an integer total
Let’s start with something easy to understand. We’ll make an array of User objects, and give each of them a score, which is just a meaningless integer value:
<?php $users = array( new User( '1000', 'name1', 'email1@example.com', 95 ), new User( '1001', 'name2', 'email2@example.com', 30 ), new User( '1002', 'name3', 'email3@example.com', 71 ), new User( '1003', 'name4', 'email4@example.com', 20 ), new User( '1004', 'name5', 'email5@example.com', 50 ), );
Now to get the total score of all the users combined, we can’t just use the array_sum function, because this is an array of objects as opposed to an array of integers. But we can work around this by using array_reduce.
<?php $total_score = array_reduce( $users, // input array function ( int $carry, User $user ) { // callback function return $carry + $user->get_score(); }, 0 // initial value );
In the above example, our input array is an array of User objects, and the initial value is zero.
To illustrate how this function works, here is a breakdown for each loop:
- For the first user, the carry is equal to the initial value: zero. It returns the sum of the carry and the user’s score.
- For the second user, the carry is equal to 95. It returns the sum of the carry and the user’s score: 125.
- For the third user, it returns a new carry of 191.
- For the fourth user, it returns a new carry of 216.
- For the fifth user, it returns a new carry of 266.
The eventual return value of the array_reduce function is equal to the carry after looping over all users. In this case it will set $total_score to 266.
Returning a nested array
I will provide another example of how the array_reduce can be used. In this case we will use the same input array of User objects as in the previous example. But instead of returning a total value, I want to group the users into brackets depending on their score:
<?php $user_score_groups = array_reduce( $users, function ( array $user_score_groups, User $user ) { $score = $user->get_score(); if ( $score <= 25 ) { $user_score_groups['0-25'][] = $user; } elseif ( $score <= 50 ) { $user_score_groups['26-50'][] = $user; } elseif ( $score <= 75 ) { $user_score_groups['51-75'][] = $user; } else { $user_score_groups['76-100'][] = $user; } return $user_score_groups; }, array( '0-25' => array(), '26-50' => array(), '51-75' => array(), '76-100' => array(), ) );
In this example, the initial value of the array_reduce function is an array consisting of empty arrays for each bracket I want to group users into.
During the callback function, I will determine which of the arrays I want to add the user to by looking at the User’s score. After adding the user, the carry can be returned.
The eventual result of this function will be an array of arrays. The innermost array will include all users belonging to that score bracket.
array_values()
The array_values function can be used to return a new array that has the same values as its input array. The difference between the input array and the result will be that the latter will have new incremental numerical keys starting from zero.
To showcase this we can use the array_filter function.
<?php $numbers = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); $even_numbers = array_filter($numbers, function(int $number) { return $number % 2 === 0; });
Let’s say we want to retrieve the first item of the $even_numbers array.
<?php $first = $even_numbers[0];
You might expect the $first variable to hold 2 as its value. But what actually happened when we filtered the $numbers array is this:
<?php array ( 1 => 2, 3 => 4, 5 => 6, 7 => 8, 9 => 10, );
As you can see, zero is no longer an index in the $even_numbers array because array_filter never assigned new indices to its result. We can fix this with the array_values function:
<?php $even_numbers = array_values($even_numbers);
And this is the result:
<?php array ( 0 => 2, 1 => 4, 2 => 6, 3 => 8, 4 => 10, );
array_keys()
This function simply returns a new array with the input array’s keys as its values.
usort()
Sorting arrays in PHP can be done in a variety of ways, but the usort function can sort an array that consists of any type of data. Whereas an array that only contains alphanumeric items can be sorted using php’s sort function, the same doesn’t apply for an array of objects. Let’s say we had the following data:
<?php $users = array( new User( '1003', 'name4', 'email4@example.com', 20 ), new User( '1001', 'name2', 'email2@example.com', 30 ), new User( '1002', 'name3', 'email3@example.com', 71 ), new User( '1000', 'name1', 'email1@example.com', 95 ), new User( '1004', 'name5', 'email5@example.com', 50 ), );
If we wanted to sort these users by their name we could use the following code:
<?php usort( $users, function ( User $user_a, User $user_b ) { $name_a = $user_a->get_name(); $name_b = $user_b->get_name(); if ( $name_a > $name_b ) { return 1; } elseif ( $name_a < $name_b ) { return - 1; } else { return 0; } } );
The callback function will compare every combination of elements. When element A is “greater than” element B, we should return 1. When it is “less than”, we should return negative 1. When both elements are equal, we should return 0. The usort function will sort and modify the original array according to these return statements.
array_chunk()
The array_chunk function can split an array into an array of multiple smaller arrays of a given maximum size. This function is useful when we want to render our data into an HTML table with a maximum number of columns.
<?php $users = array( new User( 1000, 'Jack', 'Jack@example.com' ), new User( 1001, 'Joe', 'Joe@example.com' ), new User( 1002, 'Adam', 'Adam@example.com' ), new User( 1003, 'Kelly', 'Kelly@example.com' ), new User( 1004, 'Tom', 'Tom@example.com' ), new User( 1005, 'Bill', 'Bill@example.com' ), new User( 1006, 'Anna', 'Anna@example.com' ), new User( 1007, 'Eve', 'Eve@example.com' ), ); $user_chunks = array_chunk( $users, 3 ); echo '<table>'; echo '<tbody>'; foreach ( $user_chunks as $user_chunk ) : echo '<tr>'; foreach ( $user_chunk as $user ) : echo '<td>'; echo $user->get_name(); echo '</td>'; endforeach; echo '</tr>'; endforeach; echo '</tbody>'; echo '</table>';
Jack | Joe | Adam |
Kelly | Tom | Bill |
Anna | Eve |
array_merge()
The array_merge function can be used to merge two or more arrays into a single array.
Of course we can also accomplish something similar by using the + operator but this doesn’t always work as we expect:
<?php $array_a = array(1, 2); $array_b = array(3, 4, 5, 6); $array_c = $array_a + $array_b;
You would expect $array_c to contain all values from 1 to 6 but what really happens is this:
Array ( [0] => 1 [1] => 2 [2] => 5 [3] => 6 );
Where did 3 and 4 go? They were omitted because $array_a and $array_b share the same keys for 1/3 and 2/4.
A more reliable solution is the array_merge function:
<?php $array_a = array(1, 2); $array_b = array(3, 4, 5, 6); $array_c =array_merge($array_a, $array_b);
Now, $array_c contains all the values from $array_a and $array_b:
Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 [4] => 5 [5] => 6 );
array_key_first() / array_key_last()
The array_key_last function can be useful in some situations where you want to retrieve the last element of an array but leave the original array intact.
<?php $data = array(1, 2, 3, 4, 5); $last = array_pop($data);
Using array_pop we can only accomplish the first goal, $last will contain 5. However, our original array will no longer contain 5!
<?php $data = array(1, 2, 3, 4, 5); $last = $data[sizeof($data) - 1];
That’s better, $last now contains 5, and our original array has not been touched. But this solution is not perfect. Let’s use the array_key_last function instead:
<?php $data = array(1, 2, 3, 4, 5); $last = $data[array_key_last($data)];
There are a couple of reasons why this small change would be preferable.
What if our array keys were irregular or unsorted?
<?php $data = array( 3 => 1, 40 => 2, ‘text_as_key’ => 3, 11 => 4, 1 => 5 );
Let’s try again with the first method:
<?php $last = $data[sizeof($data) - 1];
Now this code does not work anymore, it will return an error because 4 is not a defined index in our $data array.
However, if we change it to array_key_last, the $last variable will correctly contain 5:
<?php $last = $data[array_key_last($data)];
For reliably getting the first element of an array without changing the original input array, you can use the array_key_first function.
array_slice()
The array_slice function can be used to get a subset of your data.
An example array
<?php $numbers = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
The array_slice function expects at least two variables, the first being your array and the second being an offset. Let’s explore how this function behaves when we pass a positive or a negative offset.
Zero offset
<?php $subset = array_slice($numbers, 0);
Not all that useful, we get an exact copy of the input array.
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Positive offset
<?php $subset = array_slice($numbers, 3);
If the offset is positive, the first x items will not be included in the subset.
1, 2, 3, [4, 5, 6, 7, 8, 9, 10]
Negative offset
<?php $subset = array_slice($numbers, -3);
If the offset is negative, only the last x items will be included in the subset.
1, 2, 3, 4, 5, 6, 7, [8, 9, 10]
The length parameter
We can also provide an optional third “length” parameter which will also behave differently when it is negative.
Zero length
<?php $subset = array_slice($numbers, 3, 0);
A length of zero is pretty useless. An empty array will be returned every time.
Positive length
<?php $subset = array_slice($numbers, 3, 2);
When our length is a positive integer, this will be the maximum length of the resulting array.
1, 2, 3, [4, 5], 6, 7, 8, 9, 10
Excessive length
<?php $subset = array_slice($numbers, 3, 9);
When the length parameter is a maximum length for the resulting array. It will not fill the result with empty values to match the requested length.
1, 2, 3, [4, 5, 6, 7, 8, 9, 10]
Negative length
<?php $subset = array_slice($numbers, 3, -2);
What happens if our length is negative? In this case, it will exclude the last x items from the resulting array.
1, 2, 3, [4, 5, 6, 7, 8], 9, 10
Negative offset & negative length
<?php $subset = array_slice($numbers, -4, -1);
If both the offset and the length are negative, the resulting array will include the last x items, but also exclude the last y items.
1, 2, 3, 4, 5, 6, [7, 8, 9], 10
Negative offset & negative length (length smaller than offset)
<?php $subset = array_slice($numbers, -4, -5);
If a negative length is smaller than a negative offset, the resulting array will be empty.
Conclusion
I have shared some of the array functions that I personally use most commonly, but this is not a comprehensive list of all the available array functions or their usage. PHP offers many, many functions to manipulate arrays. For a detailed overview with examples you should, of course, check out the documentation!