Empowering PHP Arrays: The Magic of Laravel Collections Revealed
Tags: php, laravel, array, programming
Published: 2022-02-15 20:03:22

If you've worked with Laravel, chances are you're familiar with the powerful `Collection` class.

The Collection class (`Illuminate\Support\Collection`) is an integral part of the Illuminate Collections package, which can be found at [illuminate/collections](https://packagist.org/packages/illuminate/collections).

The Illuminate\Support\Collection class proves invaluable when dealing with data collections, offering a range of powerful methods to enhance your workflow.

The `Illuminate\Support\Collection` offers a seamless and convenient interface for handling data arrays, enhancing code readability and expressiveness.

PHP has a lot of functions to manage arrays. The PHP official documentation for array functions is: https://www.php.net/manual/en/ref.array.php

So, **why** would you need the Collection class?
There are several scenarios where using Collection instead of a PHP array is advantageous:
- when I need a superset of **additional functions**: https://laravel.com/docs/10.x/collections#available-methods;
- I want **to chain methods** to perform **fluent mapping and reducing** of the underlying array;
- because collections are **immutable**, meaning every Collection method returns an entirely new Collection instance;
- because collections are "macroable", which allows you to add additional methods to the Collection class at run time.

> If I'm working on a PHP project without Laravel Framework, can I use Collection class? The answer is **YES** 🥳🥳🥳




## Install illuminate/collections package

Begin by creating a new PHP project from scratch using [Composer](https://getcomposer.org/)

```
mkdir test-collections
cd test-collections
composer require illuminate/collections
```

The composer command generates the *composer.json* file. If you open it:

```
{
    "require": {
        "illuminate/collections": "^10.34"
    }
}
```

One important thing to know is that **Illuminate Collections 10 requires PHP 8.1**.

The dependencies of Illuminate Collections 10 are:

```
illuminate/collections   v10.34.2 The Illuminate Collections package.
illuminate/conditionable v10.34.2 The Illuminate Conditionable package.
illuminate/contracts     v10.34.2 The Illuminate Contracts package.
illuminate/macroable     v10.34.2 The Illuminate Macroable package.
psr/container            2.0.2    Common Container Interface (PHP FIG PSR-11)
psr/simple-cache         3.0.0    Common interfaces for simple caching
```

If you can't use PHP 8 for any reason (for example, if you are using PHP 7.4), consider using the previous version of the package, version 8.

| PHP Version | Collections Version |
|:---:|:---------------------------------:|
| 7.4 |                 8                 |
| 8.0 |                 9                 |
| 8.1 |                 9 or 10           |
| 8.2 |                 10                |
| 8.3 |                 10                |

I strongly suggest using an updated stack, such as PHP 8.3 (or PHP 8.2) and Illuminate Collections 10.

To install a previous version of the Illuminate Collections package:

```
composer require illuminate/collections:9.x
```

## Use Collection class

After successfully installing the package, you can begin utilizing the class. Here's how:

```php
<?php

require "vendor/autoload.php";

use Illuminate\Support\Collection;

$fruits = new Collection(['🥑', '🍒', '🍎', '🍌']);
print_r($fruits->all());
/*
Array
(
    [0] => 🥑
    [1] => 🍒
    [2] => 🍎
    [3] => 🍌
)
*/
```

You can:
- require the autoload file;
- import (via _use_ keyword) Illuminate\Support\Collection;
- instance the Object from _Collection_ class;
- use a method like _all()_ from _Collection_ class.

For instancing Collection object, you can use _new_ or calling the static method _make_:

```php
$fruits = Collection::make(['🥑', '🍒', '🍎', '🍌']);
print_r($fruits->all());
```

2 examples, same result. Under the hood, make it call and returns "new Collection()".

Additionally, you can create a custom macro, so you can add the new method at runtime to Collection object

```php
<?php

require "vendor/autoload.php";
use Illuminate\Support\Collection;

Collection::macro('blend', function () {
    return $this->map(function ($value) {
        return mb_chr(mb_ord($value) + 1);
    });
});
$fruits = Collection::make(['🥑', '🍒', '🍎', '🍌']);
$newFruits = $fruits->blend();
print_r($newFruits->all());
/*
Array
(
    [0] => 🥒
    [1] => 🍓
    [2] => 🍏
    [3] => 🍍
)
*/
```

## Collection with nested data
You can create collections with structure data (not just flat array):
```php
$collection = Collection::make([
    "avocado" =>
        [
            'name' => 'Avocado',
            'fruit' => '🥑',
            'wikipedia' => 'https://en.wikipedia.org/wiki/Avocado'
        ],
    "apple" =>
        [
            'name' => 'Apple',
            'fruit' => '🍎',
            'wikipedia' => 'https://en.wikipedia.org/wiki/Apple'
        ],
    "banana" =>
        [
            'name' => 'Banana',
            'fruit' => '🍌',
            'wikipedia' => 'https://en.wikipedia.org/wiki/Banana'
        ],
    "cherry" =>
        [
            'name' => 'Cherry',
            'fruit' => '🍒',
            'wikipedia' => 'https://en.wikipedia.org/wiki/Cherry'
        ],
]);

$filtered = $collection->whereIn('name', ['Apple', 'Banana']);

$some = $filtered->all();
print_r($some);
/*
Array
(
    [apple] => Array
        (
            [name] => Apple
            [fruit] => 🍎
            [wikipedia] => https://en.wikipedia.org/wiki/Apple
        )

    [banana] => Array
        (
            [name] => Banana
            [fruit] => 🍌
            [wikipedia] => https://en.wikipedia.org/wiki/Banana
        )

)
*/
```

## Chain methods: filtering and selecting columns
You can chain methods and custom (macro) methods.
The scenario is: you want to filter (_whereBetween_) and select some columns (_select_ macro)
```php
Collection::macro('select', function (array $fields) {
    return $this->map(function ($value, $key) use ($fields) {
        $columns = [];
        foreach ($fields as $field) {
            $columns[$field] = $value[$field];
        }
        return $columns;
    });
});

$select = $collection
    ->select(['fruit', 'name'])
    ->whereBetween('name', ['A', 'B']);
print_r($select->all());
/*
(
    [avocado] => Array
        (
            [fruit] => 🥑
            [name] => Avocado
        )

    [apple] => Array
        (
            [fruit] => 🍎
            [name] => Apple
        )

)
*/
```


## References

- Laravel Collection methods: [official doc](https://laravel.com/docs/10.x/collections#available-methods);
- Collections package on [Packagist](https://packagist.org/packages/illuminate/collections);