Laravel Deep Dives: Collections
What are Laravel Collections and Why Should We Use them?
Collections can be described as a “helper” to make working with arrays easier. Similar to my previous articles about Laravel, we’re going to do more than just explore how these work, we’re going to see how they work and why to use them.
Let's start with the basic example provided by the Laravel docs here:
$collection = collect(['taylor', 'abigail', null])->map(function (string $name) { return strtoupper($name); })->reject(function (string $name) { return empty($name); });
As we can see, the "collect" method is used to create a collection. We can then use convenience methods "map" and "reject" to iterate the collection, transform it, and eliminate any invalid entries. That's collections in a nutshell: convenient wrappers to iterate arrays.
While you can create collections manually like this, the docs note that the results of eloquent queries are always returned as collections. Most likely, that's where we will be using them the most.
How Collections Work
We can see the base "Collection" class in Illuminate\Support\Collection (view source). It shouldn't be a surprise that utility functions like "map" have a familiar implementation under the hood:
public function map(callable $callback) { $keys = array_keys($this->items); $items = array_map($callback, $this->items, $keys); return new static(array_combine($keys, $items)); }
Yes, we're just using array_map as expected. Laravel's collections are not that mysterious -- they are exactly what they claim to be: convenience wrappers for arrays. Can you use array_keys and array_map without using a Collection? Sure, but the whole point of Collections is that it is a convenience wrapper intended to reduce boilerplate code.
Reviewing the implementation of the rest of the Collection class repeats that similar story. It provides a mess of convenience methods that make working with arrays far easier. This is why it's good practice to use collections instead of relying on the (perhaps more familiar) native methods. It won't save you much (if any) performance in writing this yourself and you might need these utility methods at some point. Anything that makes your code easier to read and maintain and gives you more power and flexibility seems like an easy win.
To be clear, using Collections isn't really optional because Laravel returns them from Eloquent queries by default. You won't be saving yourself any overhead by converting the results back to an array...so you might as well accept that you must use Collections and learn to leverage the utility they provide.
How QueueableCollection Works with Eloquent
One thing you might notice if you're looking into the source code is that Eloquent results don't just use the base Collection class, they implement QueueableCollection. This gives us yet more utility by allowing us to shove eloquent results into a job to be processed in the background.
We learned about queues previously, and therefore know that this can be very beneficial. It allows the application to be unblocked while another PHP process handles background processing (most likely in a concurrent way with multi-core servers). This is why using Laravel's built-in structures is handy! With enough context, it not only saves you a lot of work, it can enable you to decouple key facets of your application logic and improve performance without having to refactor a ton of code.
With a queueable (that word has too many vowels in a row) collection, we can dispatch to a job very easily:
$models->each(function ($model) { SomeJobToDo::dispatch($model); });
Since we've already learned about how queues work, we know why queues and workers are so powerful. Learning about collections and how we can queue models so easily, it gives even more power when working with a worker-based design.
Conclusion
Collections are among the easiest Laravel concepts to understand at a low level because the implementation uses familiar array boilerplate like array_map and array_keys, which developers often use for manipulating array. It isn't tightly coupled with other Laravel concepts, so it's easy to understand without any other low-level knowledge (except maybe queues).
Still, it's worth doing this quick look into how collections are implemented and how much utility they can provide. It's especially handy to know that Eloquent results aren't just collections, they are easily queueable, too. This knowledge will help make it easier to decouple code and improve performance as applications scale.