PHPackages                             anahkiasen/underscore-php - 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. anahkiasen/underscore-php

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

anahkiasen/underscore-php
=========================

A redacted port of Underscore.js for PHP

2.0.0(11y ago)1.1k6.6M↓10.1%89[22 issues](https://github.com/Anahkiasen/underscore-php/issues)[7 PRs](https://github.com/Anahkiasen/underscore-php/pulls)20MITPHPPHP &gt;=5.4.0

Since Jan 17Pushed 8y ago39 watchersCompare

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

READMEChangelogDependencies (4)Versions (12)Used By (20)

Underscore.php
==============

[](#underscorephp)

[![Build Status](https://camo.githubusercontent.com/019b2d902ccac2afbf9a34c2359a7b828d53db42199c4115fb5df859a8e509c3/687474703a2f2f696d672e736869656c64732e696f2f7472617669732f416e61686b696173656e2f756e64657273636f72652d7068702e7376673f7374796c653d666c6174)](https://travis-ci.org/Anahkiasen/underscore-php)[![Latest Stable Version](https://camo.githubusercontent.com/4fd9c67f4e9507fb48594a4367924c934ae2458f8c087781d4017f63a897c1d8/687474703a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f616e61686b696173656e2f756e64657273636f72652d7068702e7376673f7374796c653d666c6174)](https://packagist.org/packages/anahkiasen/underscore-php)[![Total Downloads](https://camo.githubusercontent.com/7d03ee8ab896b8aeeea9b65f36dd531f7456d52b7ee17a5c8892ec7c2ec690a3/687474703a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f616e61686b696173656e2f756e64657273636f72652d7068702e7376673f7374796c653d666c6174)](https://packagist.org/packages/anahkiasen/underscore-php)[![Scrutinizer Quality Score](https://camo.githubusercontent.com/a845851318b273a2da055c61cb2c9789a2e72b5164ec06e9b25cc81569385b93/687474703a2f2f696d672e736869656c64732e696f2f7363727574696e697a65722f672f416e61686b696173656e2f756e64657273636f72652d7068702e7376673f7374796c653d666c6174)](https://scrutinizer-ci.com/g/Anahkiasen/underscore-php/)[![Code Coverage](https://camo.githubusercontent.com/14e1f285dff839333d4f4c21ee31087e388759bbab60921ca0bef449d51219f1/687474703a2f2f696d672e736869656c64732e696f2f7363727574696e697a65722f636f7665726167652f672f416e61686b696173656e2f756e64657273636f72652d7068702e7376673f7374796c653d666c6174)](https://scrutinizer-ci.com/g/Anahkiasen/underscore-php/)[![Support via Gittip](https://camo.githubusercontent.com/2700a79f496bdf434db90ac70e5e44e4b01905a98d59b74c66e7d24fcdb2e7c4/687474703a2f2f696d672e736869656c64732e696f2f6769747469702f416e61686b696173656e2e7376673f7374796c653d666c6174)](https://www.gittip.com/Anahkiasen/)

The PHP manipulation toolbelt
-----------------------------

[](#the-php-manipulation-toolbelt)

First off : Underscore.php is **not** a PHP port of [Underscore.js](https://github.com/documentcloud/underscore) (well ok I mean it was at first). It's doesn't aim to blatantly port its methods, but more port its philosophy.

It's a full-on PHP manipulation toolbet sugar-coated by an elegant syntax directly inspired by the [Laravel framework](http://laravel.com/). Out through the window went the infamous `__()`, replaced by methods and class names that are meant to be read like sentences *à la* Rails : `Arrays::from($article)->sortBy('author')->toJSON()`.

It features a good hundred of methods for all kinds of types : strings, objects, arrays, functions, integers, etc., and provides a parsing class that help switching from one type to the other mid-course. Oh also it's growing all the time. The cherry on top ? It wraps nicely around native PHP functions meaning `Strings::replace` is actually a dynamic call to `str_replace` but with the benefit of allowed chaining and a **finally** consistant argument order (**all** functions in *Underscore* put the subject as the first argument, NO MATTER WHAT).

It works both as a stand-alone via *Composer* or as a bundle for the Laravel framework. So you know, you don't really have any excuse.

Install Underscore
------------------

[](#install-underscore)

To install Underscore.php simply run `composer require anahkiasen/underscore-php`. Note that Underscore's type classes (Arrays/Strings/etc) are by default namespaced in the `Types` folder, so to use Arrays, you would do the following :

```
use Underscore\Types\Arrays;
```

Using Underscore
----------------

[](#using-underscore)

It can be used both as a static class, and an Object-Oriented class, so both the following are valid :

```
$array = array(1, 2, 3);

// One-off calls to helpers
Arrays::each($array, function($value) { return $value * $value; }) // Square the array
Function::once($myFunction) // Only allow the function to be called once
Number::paddingLeft(5, 5) // Returns '00005'
Object::methods($myObject) // Return the object's methods
Strings::length('foobar') // Returns 6

// Or chain calls with the 'from' method
Arrays::from($array)->filter(...)->sort(...)->get(2)

// Which does this in the background
$array = new Arrays($array);
$array->filter(...)->sort(...)->get(2)
```

For those nostalgic of ye old `__()` a generic `Underscore` class is provided that is able to go and fetch methods in all of Underscore.php's methods. For this it looks into the methods it knows and analyzes the subject of the method (meaning if you do `Underscore::contains('foobar', 'foo')` it knows you're not looking for `Arrays::contains`).

On types : it's important to note that using a specific type class to create an Underscore repository will convert the type of provided subject. Say you have an object and do `new Arrays($myObject)` – this will convert the object to an array and allow you to use Arrays methods on it. For this Underscore uses its **Parse** class's methods that for the most part just type cast and return (like this `(array) $object`) but it also sometimes go the extra mile to understand what you want to do : if you convert an array to a string, it will transform it to JSON, if you transform an array into an integer, it returns the size of the array, etc.

The core concept is this : static calls return values from their methods, while chained calls update the value of the object they're working on. Which means that an Underscore object don't return its value until you call the `->obtain` method on it — until then you can chain as long as you want, it will remain an object. The exception are certains properties that are considered *breakers* and that will return the object's value. An example is `Arrays->get`.

Note that since all data passed to Underscore is transformed into an object, you can do this sort of things, plus the power of chained methods, it all makes the manipulation of data a breeze.

```
$array = new Arrays(['foo' => 'bar']);

echo $array->foo // Returns 'bar'

$array->bis = 'ter'
$array->obtain() // Returns array('foo' => 'bar', 'bis' => 'ter')
```

### Customizing Underscore

[](#customizing-underscore)

Underscore.php provides the ability to extend any class with custom functions so go crazy. Don't forget that if you think you have a function anybody could enjoy, do a pull request, let everyone enjoy it !

```
Strings::extend('summary', function($string) {
  return Strings::limitWords($string, 10, '... — click to read more');
});

Strings::from($article->content)->summary()->title()
```

You can also give custom aliases to all of Underscore's methods, in the provided config file. Just add entries to the `aliases` option, the key being the alias, and the value being the method to point to.

### Extendability

[](#extendability)

Underscore.php's classes are extendable as well in an OOP sense. You can update an Underscore repository with the `setSubject` method (or directly via `$this->subject =` granted you return `$this` at the end). When creating an Underscore repository, by default it's subject is an empty string, you can change that by returning whatever you want in the `getDefault` method.

```
class Users extends Arrays
{
  public function getDefault()
  {
    return 'foobar';
  }

  public function getUsers()
  {
    // Fetch data from anywhere

    return $this->setSubject($myArrayOfUsers);
  }
}

$users = new Users; // Users holds 'foobar'
$users->getUsers()->sort('name')->clean()->toCSV()

// Same as above
Users::create()->getUsers()->sort('name')->clean()->toCSV()
```

It is important to not panic about the mass of methods present in Underscore and the dangers extending one of the Types would cause : the methods aren't contained in the classes themselves but in methods repositories. So if you extend the `Strings` class and want to have a `length` method on your class that has a completely different meaning than `Strings::length`, it won't cause any signature conflict or anything.

Also note that Underscore method router is dynamic so if your subject is an array and mid course becomes a string, Underscore will always find the right class to call, no matter what you extended in the first place. Try to keep track of your subject though : if your subject becomes a string, calling per example `->map` will return an error.

### Call to native methods

[](#call-to-native-methods)

Underscore natively extends PHP, so it can automatically reference original PHP functions when the context matches. Now, PHP by itself doesn't have a lot of conventions so `Arrays::` look for `array_` functions, `Strings::` look for `str_` plus a handful of other hardcoded redirect, but that's it. The advantage is obviously that it allows chaining on a lot of otherwise one-off functions or that only work by reference.

```
Arrays::diff($array, $array2, $array3) // Calls `array_diff`
Arrays::from($array)->diff($array2, $array3)->merge($array4) // Calls `array_diff` then `array_merge` on the result
```

Documentation
-------------

[](#documentation)

You can find a detailed summary of all classes and methods in the [repo's wiki](https://github.com/Anahkiasen/underscore-php/wiki/_pages) or the [official page](http://anahkiasen.github.com/underscore-php/). The changelog is available in the [CHANGELOG](https://github.com/Anahkiasen/underscore-php/blob/master/CHANGELOG.md) file.

About Underscore.php
--------------------

[](#about-underscorephp)

There is technically another port of Underscore.js to PHP available [on Github](https://github.com/brianhaveri/Underscore.php) — I first discovered it when I saw it was for a time used on Laravel 4. I quickly grew disapoint of what a mess the code was, the lack of updates, and the 1:1 mentality that went behind it.

This revamped Underscore.php doesn't aim to be a direct port of Underscore.js. It sometimes omits methods that aren't relevant to PHP developers, rename others to match terms that are more common to them, provides a richer syntax, adds a whole lot of methods, and leaves room for future ones to be added all the time — whereas the previous port quickly recoded all JS methods to PHP and left it at that.

If you come from Javascript and are confused by some of the changes, don't put all the blame on me for trying to mess everything up. A basic example is the `map` function : in PHP it has a completely different sense because there exists an `array_map` function that basically does what `__::invoke` does in JS. So `map` is now `Arrays::each`. Always keep in mind this was made for *PHP* developpers first, and differences **do** exist between the two to accomdate the common terms in PHP.

###  Health Score

51

—

FairBetter than 96% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity67

Solid adoption and visibility

Community41

Growing community involvement

Maturity65

Established project with proven stability

 Bus Factor1

Top contributor holds 88.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

Every ~94 days

Recently: every ~121 days

Total

10

Last Release

4020d ago

Major Versions

1.3.1 → 2.0.02015-05-16

PHP version history (2 changes)1.0.0PHP &gt;=5.3.0

1.3.1PHP &gt;=5.4.0

### Community

Maintainers

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

---

Top Contributors

[![Anahkiasen](https://avatars.githubusercontent.com/u/1321596?v=4)](https://github.com/Anahkiasen "Anahkiasen (309 commits)")[![yankeeinlondon](https://avatars.githubusercontent.com/u/980757?v=4)](https://github.com/yankeeinlondon "yankeeinlondon (21 commits)")[![sergiors](https://avatars.githubusercontent.com/u/2046276?v=4)](https://github.com/sergiors "sergiors (3 commits)")[![Dudemullet](https://avatars.githubusercontent.com/u/491242?v=4)](https://github.com/Dudemullet "Dudemullet (3 commits)")[![karolisg](https://avatars.githubusercontent.com/u/1695346?v=4)](https://github.com/karolisg "karolisg (2 commits)")[![khayyam90](https://avatars.githubusercontent.com/u/824766?v=4)](https://github.com/khayyam90 "khayyam90 (2 commits)")[![mcordingley](https://avatars.githubusercontent.com/u/1084253?v=4)](https://github.com/mcordingley "mcordingley (2 commits)")[![syphernl](https://avatars.githubusercontent.com/u/639906?v=4)](https://github.com/syphernl "syphernl (1 commits)")[![wjlroe](https://avatars.githubusercontent.com/u/43315?v=4)](https://github.com/wjlroe "wjlroe (1 commits)")[![ciarand](https://avatars.githubusercontent.com/u/2149341?v=4)](https://github.com/ciarand "ciarand (1 commits)")[![blessingefkt](https://avatars.githubusercontent.com/u/887992?v=4)](https://github.com/blessingefkt "blessingefkt (1 commits)")[![D1kz](https://avatars.githubusercontent.com/u/974082?v=4)](https://github.com/D1kz "D1kz (1 commits)")[![harryxu](https://avatars.githubusercontent.com/u/9913?v=4)](https://github.com/harryxu "harryxu (1 commits)")[![mauvm](https://avatars.githubusercontent.com/u/1067696?v=4)](https://github.com/mauvm "mauvm (1 commits)")[![nesk](https://avatars.githubusercontent.com/u/817508?v=4)](https://github.com/nesk "nesk (1 commits)")

---

Tags

laraveltoolkitinternals

###  Code Quality

TestsPHPUnit

### Embed Badge

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

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

###  Alternatives

[jasonlam604/stringizer

Stringizer is a PHP string manipulation library with support for method chaining and multibyte handling

35110.5k1](/packages/jasonlam604-stringizer)[tlr/menu

Take some of the stress and boilerplate out of building menus (or indeed any list, because that's basically what a menu is) With support for laravel

189.6k](/packages/tlr-menu)

PHPackages © 2026

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