PHP Collections: Array to Map
Tags: php, array, tutorial, collection
Published: 2020-01-07 16:34:56

**Arrays** are the working horse of PHP, the programming language used by the vast majority of web applications. An array seems to be incredible simple to use but things get **complicated and ugly** when PHP functions for **array manipulation** come into play. Are you tired of hard to read code with excessive error handling too? Then **collections** can be the answer.

- [Documentation at Github](https://github.com/aimeos/map)
- [Composer package on Packagist](https://packagist.org/packages/aimeos/map)

## Why?

Here’s a common example of how array manipulation is done in most PHP code:

```
$list = [
    ['id' => 'one', 'value' => 'value1'],
    ['id' => 'two', 'value' => 'value2'],
    null
];

$list[] = ['id' => 'three', 'value' => 'value3'];    // add element
unset( $list[0] );                                   // remove element
$list = array_filter( $list );                       // remove empty values
sort( $list );                                       // sort elements
$pairs = array_column( $list, 'value', 'id' );       // create ['three' => 'value3']
$value = reset( $pairs ) ?: null;                    // return first value
```

It adds/removes elements, sorts and transforms the content and retrieves the first element. You can’t write that shorter or more elegant and moreover, you need to check almost all array functions for errors.

## Using maps

The [map composer package](https://packagist.org/packages/aimeos/map) offers an easy API comparable to jQuery or Laravel collections:

```
composer req aimeos/map
```

When using the Map object, you can do the same as above more elegant with less code:

```
$list = [
    ['id' => 'one', 'value' => 'value1'],
    ['id' => 'two', 'value' => 'value2'],
    null
];

$value = map( $list )                                // create Map
    ->push( ['id' => 'three', 'value' => 'value3'] ) // add element
    ->remove( 0 )                                    // remove element
    ->filter()                                       // remove empty values
    ->sort()                                         // sort elements
    ->col( 'value', 'id' )                           // create ['three' => 'value3']
    ->first();                                       // return first value
```

And contrary to PHP arrays, you don’t have to care about error handling because either, there are no errors possible or the Map object will throw an exception if something is really wrong.

Of course, you can use the Map object still like a plain PHP array:

```
$map[] = ['id' => 'three', 'value' => 'value3'];
$value = $map[0];
count( $map );
foreach( $map as $key => value );
```

In addition, Map objects allow you to pass anonymous functions to a lot of methods. Thus, you can process and transform the elements according to your current needs, e.g. using the `each()` method:

```
$map->each( function( $val, $key ) {
	echo $key . ': ' . $val;
} );
```

You can even extend Maps dynamically by own methods. This is especially useful if you need a transformation of the Map elements more often and at several places of your code:

```
Map::method( 'strrev', function( $sep ) {
    return strrev( join( '-', $this->items ) );
} );
Map::from( ['a', 'b'] )->strrev( '-' );
```

The best part is using a Map like a jQuery object, where methods are applied to all objects of the Map. Then, you can create expressive code in one line:

```
class MyClass {
    private $code;
    private $status;
 
    public function __construct( $code ) { $this->code = $code; }
    public function setStatus( $s ) { $this->stat = $s; return $this; }
    public function getCode() { return $this->code; }
}
 
$objects = Map::from( ['a' => new MyClass( 'x' ), 'b' => new MyClass( 'y' )] );
$result = $objects->setStatus( 1 )->getCode()->toArray();
```

The example will call `setStatus(1)` on all objects and creates a new Map with the returned values. Because `setStatus()` returns the same object (`$this`), we can apply another method on all objects afterwards (`getCode()`). The results of `getCode()` is wrapped in a Map object again and `toArray()` returns a plain PHP array which consists of:

```
['a' => 'x', 'b' => 'y']
```

## Available methods

The Map object contains methods for almost all array functions available and more like `collapse()`, `flat()`, `toJson()` or methods found in the Javascript Array prototype. Here’s a list of its methods and for documentation, have a look at the Map readme at GitHub where you can also check the code.

**function map()** : Creates a new map from elements
**arsort()** : Reverse sort elements with keys
**asort()** : Sort elements with keys
**chunk()** : Splits the map into chunks
**clear()** : Removes all elements
**col()** : Creates a key/value mapping
**collapse()** : Collapses multi-dimensional elements
**concat()** : Combines the elements
**copy()** : Creates a new copy
**count()** : Returns the number of elements
**diff()** : Returns the missing elements
**diffAssoc()** : Returns the missing elements and checks keys
**diffKeys()** : Returns the missing elements by keys
**each()** : Applies a callback to each element
**empty()** : Tests if map is empty
**equals()** : Tests if map contents are equal
**filter()** : Applies a filter to the map elements
**find()** : Returns the first matching element
**first()** : Returns the first element
**flip()** : Exchanges keys with their values
**flat()** : Flattens multi-dimensional elements
**from()** : Creates a new map from passed elements
**get()** : Returns an element by key
**has()** : Tests if a key exists
**in()** : Tests if element is included
**includes()** : Tests if element is included
**intersect()** : Returns the shared elements
**intersectAssoc()** : Returns the shared elements and checks keys
**intersectKeys()** : Returns the shared elements by keys
**isEmpty()** : Tests if map is empty
**join()** : Returns concatenated elements as string
**keys()** : Returns the keys
**krsort()** : Reverse sort elements by keys
**ksort()** : Sort elements by keys
**last()** : Returns the last element
**map()** : Applies a callback to each element and returns the results
**merge()** : Combines elements overwriting existing ones
**method()** : Registers a custom method
**pipe()** : Applies a callback to the map
**pop()** : Returns and removes the last element
**pull()** : Returns and removes an element by key
**push()** : Adds an element to the end
**random()** : Returns random elements
**reduce()** : Computes a value for the map content
**remove()** : Removes an element by key
**replace()** : Replaces elements recursively
**reverse()** : Reverses the array order
**rsort()** : Reverse sort elements
**search()** : Find the key of an element
**set()** : Overwrites an element
**shift()** : Returns and removes the first element
**shuffle()** : Randomizes the element order
**slice()** : Returns a slice of the map
**sort()** : Sorts elements
**split()** : Splits a string into map elements
**splice()** : Replaces a slice by new elements
**toArray()** : Returns the plain array
**toJson()** : Returns the elements in JSON format
**uasort()** : Sorts elements with keys using callback
**uksort()** : Sorts elements by keys using callback
**union()** : Combines the element without overwriting
**unique()** : Returns unique elements
**unshift()** : Adds an element at the beginning
**usort()** : Sorts elements using callback
**values()** : Returns all elements with new keys

Again, the [Map documentation](https://github.com/aimeos/map#methods) offers descriptions, explains parameters/return values and has examples for each method. Some methods are even better documented than the corresponding PHP array function.

## Conclusion

Map objects are an easy to use and elegant way to handle PHP arrays. After using it for a while you won’t want to remember the times before. If you’ve already worked with jQuery and like it’s simplicity, you will feel like home when using appropriate lists of objects in your application.

As the Map methods are using the native array functions or are highly optimized, it’s also save to use them in large scale applications. The documentation contains a section about the [Map performance](https://github.com/aimeos/map#methods) and hints to avoid performance bottlenecks.