Stop using for loops and start showing intent
Tags: php, webdev, programming
Published: 2023-02-28 14:17:27

Over the years I keep seeing people abuse the very popular for loops. This powerful tool allows you to go over entire lists of items and do things with them. The biggest downside to these is that need to read the entire loop in order to discover what it does. Luckily most programming languages these days provide multiple functions that you can apply to your lists and/or arrays of data to get the same results, but with shown intent!

In this article I will show you the most used functions and how they work with the help of PHP.

## Before we start
Before we start I will set up a small amount of classes and variables that will be used as examples further into the article.

```php
class Movie {
    public function __construct(
        public string $title,
        public string $genre,
        public int $rating
    ) {}
}

$moviesAsJson = [
    [
        'title' => 'John Wick',
        'genre' => 'action',
        'rating' => 86,
    ],
    [
        'title' => 'Frozen',
        'genre' => 'kids&family',
        'rating' => 90,
    ],
    [
        'title' => 'Hot Fuzz',
        'genre' => 'action',
        'rating' => 91,
    ],
    [
        'title' => 'Scott Pilgrim vs. the World',
        'genre' => 'comedy',
        'rating' => 82,
    ],
];
```

## Examples of the functions
The examples given in this section will probably be of the same length of code as the examples while using foreach loops, so you will probably think that these functions are not very special. 

Keep in mind that the actual code will almost always be longer, so you will need to read the *entire* foreach loop to see what the intention of the writer was. To keep the code simple I chose to use short examples.

### Transforming data
Let's start with one of the functions I use the most. It's the map function. This function is used to transform data in an array to something completely different. We will use the result of this transformation in the following examples.
```php
$movies = []
foreach ($moviesAsJson as $movie) {
    $movies[] = new Movie(
        $movie['title'],
        $movie['genre'],
        $movie['rating']
    );
}

$movies = array_map(
    fn (array $movie) => new Movie(
        $movie['title'],
        $movie['genre'],
        $movie['rating']
    ),
    $moviesAsJson,
);
```

### Filtering
Sometimes you might even need to filter data from an array. Let's say I only want a list of action movies. If you don't use array methods you will write something like this.
```php
$actionMovies = []
foreach ($movies as $movie) {
    if ($movie->genre === 'action') {
        $actionMovies[] = $movie;
    }
}
```

This can be made a lot more clear if you use the filter method. 
```php
$actionMovies = array_filter(
    $movies,
    fn (Movie $movie) => $movie->genre === 'action'
);
```

### Reducing array to a new value
The reduce method usually is one of the more confusing ones in the entire suite. It is used to reduce an entire array to a single value. To demonstrate the power of this method I will give two examples.

First I want the movies to be grouped by genre. This way I can easily display the movies in their own sections without having to use an array_filter!

```php
$moviesByGenre = [];
foreach ($movies as $movie) {
    $moviesByGenre[$movie->genre] ??= [];
    $moviesByGenre[$movie->genre][] = $movie;
}
```
Now this is what it would look like using the reduce function.
```php
$moviesByGenre = array_reduce(
    $movies,
    function (array $moviesByGenre, Movie $movie) {
        $moviesByGenre[$movie->genre] ??= [];
        $moviesByGenre[$movie->genre][] = $movie;

        return $moviesByGenre;
    },
    []
);
```

Another usual use of the reduce function is to calculate values. Let's say we want the average rating of the given movies.
```php
$totalRating = 0;

foreach ($movies as $movie) {
    $totalRating += $movie->rating;
}

$averageRating = $totalRating / count($movies);
```

This is what it would look like using array reduce
```php
$totalRating = array_reduce(
    $movies,
    fn (int $totalRating, Movie $movie) => $totalRating + $movie->rating,
    0
);

$averageRating = $totalRating / count($movies);
```

## Conclusion
The array functions allow the reader to instantly read the intent of what you want to do with your array. They won't have to sift through the entire foreach loop and thus they can immediately focus on whats being altered/filtered/reduced.