PHPackages                             thinkingmedia/underscore - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. thinkingmedia/underscore

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

thinkingmedia/underscore
========================

Underscore is a PHP library that provides useful helpers when working with arrays and collections.

1.0.0(11y ago)0301[1 issues](https://github.com/thinkingmedia/underscore/issues)1BSD-2-ClausePHPPHP &gt;=5.4.0

Since Mar 19Pushed 10y ago1 watchersCompare

[ Source](https://github.com/thinkingmedia/underscore)[ Packagist](https://packagist.org/packages/thinkingmedia/underscore)[ Docs](https://github.com/thinkingmedia/underscore)[ RSS](/packages/thinkingmedia-underscore/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (1)Dependencies (1)Versions (2)Used By (1)

Underscore
==========

[](#underscore)

[![Build Status](https://camo.githubusercontent.com/b3dd9c4dc456c695414a10f2b93b5871e0b021f092176e99fdcea388151a9919/68747470733a2f2f7472617669732d63692e6f72672f7468696e6b696e676d656469612f756e64657273636f72652e737667)](https://travis-ci.org/thinkingmedia/underscore)[![Coverage Status](https://camo.githubusercontent.com/e2d6b89033ba0a70dababcfb7154fd45c6e2fe49a470ebe09f718effce27f7b4/68747470733a2f2f636f766572616c6c732e696f2f7265706f732f7468696e6b696e676d656469612f756e64657273636f72652f62616467652e737667)](https://coveralls.io/r/thinkingmedia/underscore)[![Latest Stable Version](https://camo.githubusercontent.com/4d74e2dab889671ab63dbf4d2d3e9efe357b0b3ae43b89ef3a7d26cc94c87753/68747470733a2f2f706f7365722e707567782e6f72672f7468696e6b696e676d656469612f756e64657273636f72652f762f737461626c652e737667)](https://packagist.org/packages/thinkingmedia/underscore)[![Total Downloads](https://camo.githubusercontent.com/aa05f694ddda1362c33de00ba9648da33179b2e61134b72816bead8cb13efd4f/68747470733a2f2f706f7365722e707567782e6f72672f7468696e6b696e676d656469612f756e64657273636f72652f646f776e6c6f6164732e737667)](https://packagist.org/packages/thinkingmedia/underscore)[![Latest Unstable Version](https://camo.githubusercontent.com/f4fec54085e68a6c547f6c2bcb2e9f2f8f47a220a48c5ebdb8cded9c272f66a8/68747470733a2f2f706f7365722e707567782e6f72672f7468696e6b696e676d656469612f756e64657273636f72652f762f756e737461626c652e737667)](https://packagist.org/packages/thinkingmedia/underscore)[![License](https://camo.githubusercontent.com/1e8294a2b4b89ffd90fdc1f803ab368f3575573aa2c4665021541bb1c1e3d04a/68747470733a2f2f706f7365722e707567782e6f72672f7468696e6b696e676d656469612f756e64657273636f72652f6c6963656e73652e737667)](https://packagist.org/packages/thinkingmedia/underscore)

`Underscore` is an utility library that makes working with arrays in PHP a little bit more pleasant.

Installation
------------

[](#installation)

Via Composer

```
$ composer require thinkingmedia/underscore

```

Usage
-----

[](#usage)

The following examples assume that you have included the Underscore utility:

```
use Underscore\_;

```

Some of the examples might seem a bit contrived, but they're actually really handy. For example, let's say that we have a fictional social network and (for some reason) we want to get the names of all the authenticated user's 2nd degree friends (friends-of-friends) that are over the age of 18. Suddenly, that becomes real easy!

```
_::create($user->getFriends())->map(function ($f) {
    return $f->getFriends();
})->select(function ($f) {
    return $f->getAge() > 18;
})->pluck('username');

```

And now (for some even stranger reason) we want to know the total number of *third* degree friends (friends-of-friends-of-friends) of the 2nd degree friends that are over the age of 18.

```
_::create($user->getFriends())->map(function ($f) {
    return $f->getFriends();
})->select(function ($f) {
    return $f->getAge() > 18;
})->reduce(function ($s, $f) {
    return $s + count($f->getFriends());
});

```

That's it!

> **Note**: When, in the examples, the return value comment indicates an array the actual return value is a new `_` instance! You can get the actual PHP array value by calling the `toArray` method.

The `_` class implements `ArrayAccess` too, so you can access it like an usual array:

```
$groups = _::create($user->getFriends())->groupBy(function ($friend) {
    $name = $friend->getName();

    return $name[0];
});

$groups['A'] = ...; // All friends with the letter 'A' as the first letter in their name

```

Additionally, you can traverse the container in a `foreach` loop as well:

```
$users = _::create(['alice', 1337, 'bob', 42])->chunk(2);

foreach ($users as $name => $karma) {
    // ...
}

```

#### `all`

[](#all)

Call the given `callback` for each element in the container. Should the callback return `false`, the method immediately returns `false` and ceases enumeration. If all invocations of the callback return `true`, `all` returns `true`.

```
_::create([1, 2, 3])->all(function ($n) {
    return $n > 0;
}); // true

```

#### `any`

[](#any)

Call the given `callback` for each element in the container. Should the callback return `true`, the method immediately returns `true` and enumeration is ceased. If all invocations of the callback return `false`, `any` returns `false`.

```
_::create([1, 2, 3])->any(function ($n) {
    return $n > 2;
}); // true

```

#### `chunk`

[](#chunk)

Chunks the container into a new array of `n`-sized chunks.

```
_::create([1, 2, 3, 4])->chunk(2); // [[1, 2], [3, 4]]

```

#### `combine`

[](#combine)

Combine the container with another array into key/value pairs.

```
_::create([1, 2, 3])->combine(['foo', 'bar', 'baz']); // [1 => 'foo', 2 => 'bar', 3 => 'baz']

```

#### `concat`

[](#concat)

Returns a new array that is the container with the given `array` concatenated to the end.

```
_::create([1, 2])->concat([3, 4]); // [1, 2, 3, 4]

```

#### `dict`

[](#dict)

Convert an array of key/value pairs into the logical dictionary.

```
_::create([[1, 2], [3, 4]])->dict(); // [1 => 2, 3 => 4]

```

If you have a flat array you can call `chunk(2)` before `dict`.

```
_::create([1, 2, 3, 4])->chunk(2)->dict(); // [1 => 2, 3 => 4]

```

#### `each`

[](#each)

Calls the given callback once for each element in the container, passing that element as the argument.

```
_::create([1, 2, 3, 4])->each(function ($n) {
    printf("%d\n", $n);
}); // outputs: 1\n2\n3\n4\n

```

`each` also supports two and three parameter versions:

```
_::create([1, 2, 3, 4])->each(function ($n, $i) {
    printf("%d: %d\n", $i, $n);
}); //outputs: 0: 1\n1: 2\n2: 3\n3: 4\n

_::create([1, 2, 3, 4]->each(function ($n, $i, $array) {
    // ...
}));

```

#### `find`

[](#find)

Passes each entry in the container to the given callback, returning the first element for which callback is not `false`. If no entry matches, returns `null`.

```
_::create([1, 2, 3, 4])->find(function ($n) {
    return $n > 2;
}); // 3

```

#### `first`

[](#first)

Returns the first `n` elements in the container.

```
_::create([1, 2, 3, 4])->first(2); // [1, 2]

```

#### `flatten`

[](#flatten)

Returns a new, one-dimensional array that is a recursive flattening of the container.

```
_::create([1, [2], [3, [4]]])->flatten(); [1, 2, 3, 4]

```

> **Tip:** If you only want to flatten one level of an array, `flatMap` might be useful for you!

#### `flatMap`

[](#flatmap)

Returns a new array with the concatenated results of invoking the callback once for every element in the container.

```
_::create([1, 2, 3, 4])->flatMap(function ($n) {
    return [$n, $n];
}); // [1, 1, 2, 2, 3, 3, 4, 4]

_::create([1, 2, 3, 4])->flatMap(function ($n) {
    return [$n, [$n]];
}); // [1, [1], 2, [2], 3, [3], 4, [4]]

```

It might look a bit silly, but this is actually a really useful function when you combine it with other functions! For example, you can create a dictionary for (fictional) users.

```
_::create([new User('bob', 32), new User('alice', 35)])->flatMap(function ($u) {
    return [$n->getName(), $n->getAge()];
})->chunk(2)->dict(); // ['bob' => 32, 'alice' => 35]

```

Which finally allows us, as developers, to create key/value pairs when mapping arrays! Hoorah!

#### `groupBy`

[](#groupby)

Groups the container by result of the given callback.

```
_::create([1, 2, 3, 4])->groupBy(function ($n) {
    return $n % 2;
}); // [0 => [2, 4], 1 => [1, 3]]

_::create(['foo', 'bar', 'baz'])->groupBy(function ($s) {
    return $s[0];
}); // ['f' => ['foo'], 'b' => ['bar', 'baz']]

```

#### `has`

[](#has)

```
_::create([1, 2, 3, 4])->has(2); // true
_::create([1, 2, 3, 4])->has(0); // false

```

#### `indexOf`

[](#indexof)

Returns the index of the given object in the container or `null` if the element was not found.

```
_::create([1, 2, 3, 4])->indexOf(2); // 1
_::create([1, 2, 3, 4])->indexOf(0); // null

```

#### `inject`

[](#inject)

Combines all elements of the container by applying a binary operation.

```
_::create([1, 2, 3])->inject([], function ($m, $n) {
    $m[$n] = $n * $n;

    return $m;
}); // [1 => 1, 2 => 4, 3 => 9]

_::create(['foo', 'bar', 'baz'])->inject('', function ($m, $s) {
    $m .= $s;
}); // foobarbaz

```

> **Note**: This is the only exception to the note earlier. The return value here is the return value of the *last* itertation.

#### `join`

[](#join)

Returns a string of all the container's elements joined with the provided separator string.

```
_::create([1, 2, 3, 4])->join('');  // 1234
_::create([1, 2, 3, 4])->join(','); // 1,2,3,4

```

#### `last`

[](#last)

Returns the last `n` elements from the container.

```
_::create([1, 2, 3, 4, 5, 6])->last(2); // [5, 6]

```

#### `map`

[](#map)

Invokes the given callback for each element in the container. Creates a new array containing the values returned by the block.

If the given callback returns `null`, that element is skipped in the returned array.

```
_::create([1, 2, 3, 4])->map(function ($n) {
    return $n * $n;
}); // [1, 4, 9, 16]

_::create([1, 2, 3, 4])->map(function ($n) {
    return $n % 2 ? $n * $n : null;
}); // [1, 9]

```

#### `max`

[](#max)

Returns the element for which the given callback returns the largest integer.

```
_::create('1', 'two', 'three')->max(function ($s) {
    return strlen($s);
}); // 'three'

```

#### `min`

[](#min)

Returns the element for which the given callback returns the smallest integer.

```
_::create('1', 'two', 'three')->min(function ($s) {
    return strlen($s);
}); // '1'

```

#### `none`

[](#none)

Test if the given callback returns `false` for each element in the container.

```
_::create([1, 2, 3, 4])->none(function ($n) {
    return $n < 0;
}); // true

_::create([1, 2, 3, 4])->none(function ($n) {
    return $n > 0;
}); // false

```

#### `partition`

[](#partition)

Partitions the container into two arrays based on the boolean return value of the given block.

```
_::create(['A', 'B', 'C', 'AA'])->partition(function ($s) {
    return $s[0] == 'A';
}); // [['A', 'AA'], ['B', 'C']]

```

#### `pluck`

[](#pluck)

Returns a new array that is the result of retrieving the given property path on each element in the container.

```
_::create([new User('bob'), new User('alice')])->pluck('username'); // ['bob', 'alice']

```

#### `product`

[](#product)

Calculate the product of the container by assuming that all values can be casted to a double value.

```
_::create([1, 2, 3])->product(); // 6

```

#### `reduce`

[](#reduce)

Reduces the container to a single value.

The usual example of reduce is to sum all values in an array.

```
_::create([1, 2, 3, 4])->reduce(function ($memo, $n) {
    return $memo + $n;
}); // 10

```

Reduce also allows you to set an initial value before reducing the array.

```
_::create([1, 2, 3, 4])->reduce(function ($s, $n) {
    return $s + $n;
}, 10); // 20

```

#### `reject`

[](#reject)

Returns a new array containing all elements for which the given callback returns `false`.

```
_::create([1, 2, 3, 4])->reject(function ($n) {
    return ($n % 2) == 0;
}); // [1, 3]

```

#### `reverse`

[](#reverse)

Returns a new array that is the container, reversed.

```
_::create([1, 2, 3, 4])->reverse(); // [4, 3, 2, 1]

```

#### `rotate`

[](#rotate)

Returns a new array rotated about the provided index.

```
_::create([1, 2, 3, 4, 5, 6])->rotate(2); // [3, 4, 5, 6, 1, 2]
_::create([1, 2, 3, 4, 5, 6])->rotate(-2); // [5, 6, 1, 2, 3, 4]

```

#### `sample`

[](#sample)

Returns a random element from the container.

```
_::create([1, 2, 3, 4, 5, 6])->sample(); // Basically a dice roll...

```

#### `select`

[](#select)

Returns a new array containing all elements for which the given block returns `true`.

```
_::create([1, 2, 3, 4])->select(function ($n) {
    return ($n % 2) == 0;
}); // [2, 4]

```

#### `shuffle`

[](#shuffle)

Returns a new array that is shuffled.

```
_::create([1, 2])->shuffle(); // Either [1, 2] or [2, 1]

```

#### `skip`

[](#skip)

Skips the first `n` elements and returns the rest of the array.

```
_::create([1, 2, 3, 4, 5, 6])->skip(2); // [3, 4, 5, 6]

```

#### `slice`

[](#slice)

Returns a subarray consisting of the given number of elements from the given starting index.

```
_::create([1, 2, 3, 4])->slice(1, 2); // [2, 3]

```

#### `snip`

[](#snip)

Snips the end off the array. Returns the container *without* the last `n`elements.

```
_::create([1, 2, 3, 4, 5, 6])->snip(2); // [1, 2, 3, 4]

```

#### `sort`

[](#sort)

Returns the container, sorted.

```
_::create([1, 4, 2, 3])->sort(); // [1, 2, 3, 4]

```

#### `sortBy`

[](#sortby)

Sorts all objects using the return value of the given callback as the sorting criteria.

```
$rhombas = new Shape('rhombas');
$ellipse = new Shape('ellipse');
$hexagon = new Shape('hexagon');

_::create([ $rhombas, $ellipse, $hexagon ])->sortBy(function ($s) {
    return $s->getName();
}); // [ $ellipse, $hexagon, $rhombas ]

```

#### `sum`

[](#sum)

Sum all objects by casting the values to a double.

```
_::create([1, 2, 3, 4])->sum(); // 10

```

#### `transpose`

[](#transpose)

Assumes that the container is an array of arrays and transposes the rows and columns.

```
_::create([[1, 2, 3], [4, 5, 6]])->transpose(); // [[1, 4], [2, 5], [3, 6]]

```

#### `uniq`

[](#uniq)

Returns a new array by removing duplicate values in the container.

```
_::create([1, 2, 3, 1, 2, 4, 1, 2, 5])->uniq(); // [3, 4, 5]

```

#### `without`

[](#without)

Returns a new array where objects in the given array are removed from the container.

```
_::create([1, 2, 4, 3])->without([4]); // [1, 2, 3]
_::create([1, 2, 3, 4, 5])->without([4, 5]); // [1, 2, 3]

```

#### `pop`

[](#pop)

Treats container like a stack and removes the last object, returning it.

```
_::create()->push(1)->push(2)->push(3)->pop(); // 3

```

#### `push`

[](#push)

Treats container like a stack and adds the given object to the end of the container.

```
_::create()->push(1)->push(2)->push(3); // [1, 2, 3]

```

#### `shift`

[](#shift)

Removes the container's first object and returns it.

```
_::create([1, 2, 3])->shift(); // 1

```

#### `unshift`

[](#unshift)

Inserts the given object at the front of container, moving all other objects in the container up one index.

```
_::create([2, 3])->unshift(1); // [1, 2, 3]

```

#### `split`

[](#split)

Returns a new array of the strings in the given string that are separated by the given separator.

```
_::split('foo bar baz', ' '); // ['foo', 'bar', 'baz']

```

The second parameter is optional and `null` by default, if you pass `null` or an empty string as seperator, you will get an array of the individual characters in the given string.

```
_::split('1234'); // ['1', '2', '3', '4']

```

We can do some pretty neat stuff with this!

```
_::split('1234')->sum(); // 10

```

#### `first`, `last`, `skip`, `snip` &amp; `slice`

[](#first-last-skip-snip--slice)

These functions are strongly related and useful to remember.

```
_::create([1, 2, 3, 4, 5])->first(2);       // [1, 2]
_::create([1, 2, 3, 4, 5])->last(2);        // [4, 5]
_::create([1, 2, 3, 4, 5])->skip(2);        // [3, 4, 5]
_::create([1, 2, 3, 4, 5])->snip(2);        // [1, 2, 3]
_::create([1, 2, 3, 4, 5])->slice(2, 2);    // [3, 4]

```

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](https://github.com/thinkingmedia/underscore/blob/master/CONTRIBUTING.md).

Credits
-------

[](#credits)

This project is heavily inspired by [YOLOKit](http://mxcl.github.io/YOLOKit/). For all of you who develop in Objective-C, I highly recommend you check it out!

License
-------

[](#license)

Please see [LICENSE](https://github.com/thinkingmedia/underscore/blob/master/LICENSE).

###  Health Score

28

—

LowBetter than 54% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity12

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity58

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 98.3% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

4078d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/d7426ad19db0720d01e6e69652d1bf4f934a57ae9dcd29f6cdf4f9811c562463?d=identicon)[thinkingmedia](/maintainers/thinkingmedia)

---

Top Contributors

[![kleiram](https://avatars.githubusercontent.com/u/323498?v=4)](https://github.com/kleiram "kleiram (57 commits)")[![thinkingmedia](https://avatars.githubusercontent.com/u/551022?v=4)](https://github.com/thinkingmedia "thinkingmedia (1 commits)")

---

Tags

arraycollectionsunderscoretoolkit

### Embed Badge

![Health badge](/badges/thinkingmedia-underscore/health.svg)

```
[![Health](https://phpackages.com/badges/thinkingmedia-underscore/health.svg)](https://phpackages.com/packages/thinkingmedia-underscore)
```

###  Alternatives

[doctrine/collections

PHP Doctrine Collections library that adds additional functionality on top of PHP arrays.

6.0k411.1M1.2k](/packages/doctrine-collections)[ginq/ginq

LINQ to Object inspired DSL for PHP

192257.5k3](/packages/ginq-ginq)[malarzm/collections

Various implementations of Doctrine's Collection interface

2368.1k](/packages/malarzm-collections)[vistik/typed-collections

A simple way to create typed collections in PHP - build on Illuminate\\Support\\Collection

1128.2k5](/packages/vistik-typed-collections)[blainesch/prettyarray

Manipulate arrays similar to Ruby.

1119.2k](/packages/blainesch-prettyarray)[rotexsoft/versatile-collections

A collection package that can be extended to implement things such as a Dependency Injection Container, RecordSet objects for housing database records, a bag of http cookies, or technically any collection of items that can be looped over and whose items can each be accessed using array-access syntax or object property syntax.

186.0k1](/packages/rotexsoft-versatile-collections)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
