Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/adhocore/php-underscore
PHP underscore inspired &/or cloned from _.js, with extra goodies like higher order messaging
https://github.com/adhocore/php-underscore
adhocore array-utils arrayify arrayize collection collections fluent fluent-interface higher-order-message lodash-php php php-collection php-functional php-underscore throttle-function underscore
Last synced: 19 days ago
JSON representation
PHP underscore inspired &/or cloned from _.js, with extra goodies like higher order messaging
- Host: GitHub
- URL: https://github.com/adhocore/php-underscore
- Owner: adhocore
- License: mit
- Created: 2017-10-26T16:27:47.000Z (about 7 years ago)
- Default Branch: main
- Last Pushed: 2023-03-25T14:30:34.000Z (over 1 year ago)
- Last Synced: 2024-10-17T07:38:00.891Z (about 1 month ago)
- Topics: adhocore, array-utils, arrayify, arrayize, collection, collections, fluent, fluent-interface, higher-order-message, lodash-php, php, php-collection, php-functional, php-underscore, throttle-function, underscore
- Language: PHP
- Homepage:
- Size: 114 KB
- Stars: 44
- Watchers: 2
- Forks: 6
- Open Issues: 0
-
Metadata Files:
- Readme: readme.md
- Changelog: CHANGELOG.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
## adhocore/underscore
PHP underscore inspired &/or cloned from awesome `_.js`. A set of utilities and data manipulation helpers providing convenience functionalites to deal with array, list, hash, functions and so on in a neat elegant and OOP way. Guaranteed to save you tons of boiler plate codes when churning complex data collection.
[![Latest Version](https://img.shields.io/github/release/adhocore/php-underscore.svg?style=flat-square)](https://github.com/adhocore/php-underscore/releases)
[![Travis Build](https://img.shields.io/travis/adhocore/php-underscore/master.svg?style=flat-square)](https://travis-ci.org/adhocore/php-underscore?branch=master)
[![Scrutinizer CI](https://img.shields.io/scrutinizer/g/adhocore/php-underscore.svg?style=flat-square)](https://scrutinizer-ci.com/g/adhocore/php-underscore/?branch=master)
[![Codecov branch](https://img.shields.io/codecov/c/github/adhocore/php-underscore/master.svg?style=flat-square)](https://codecov.io/gh/adhocore/php-underscore)
[![StyleCI](https://styleci.io/repos/108437038/shield)](https://styleci.io/repos/108437038)
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE)
[![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=Functional+programming+paradigm+in+PHP+to+manipulate+arrays+like+pro&url=https://github.com/adhocore/php-underscore&hashtags=php,functional,array,collection)
[![Support](https://img.shields.io/static/v1?label=Support&message=%E2%9D%A4&logo=GitHub)](https://github.com/sponsors/adhocore)- Zero dependency (no vendor bloat).
## Installation
Requires PHP5.6 or later.
```sh
composer require adhocore/underscore
```## Usage and API
Although all of them are available with helper function `underscore($data)` or `new Ahc\Underscore($data)`,
the methods are grouped and organized in different heriarchy and classes according as their scope.
This keeps it maintainable and saves from having a God class.#### Contents
- [Underscore](#underscore)
- [UnderscoreFunction](#underscorefunction)
- [UnderscoreArray](#underscorearray)
- [UnderscoreCollection](#underscorecollection)
- [UnderscoreBase](#underscorebase)
- [HigherOrderMessage](#higherordermessage)
- [ArrayAccess](#arrayaccess)
- [Arrayizes](#arrayizes)---
### Underscore
constant(mixed $value): callableGenerates a function that always returns a constant value.
```php
$fn = underscore()->constant([1, 2]);$fn(); // [1, 2]
```
noop(): voidNo operation!
```php
underscore()->noop(); // void/null
```
random(int $min, int $max): intReturn a random integer between min and max (inclusive).
```php
$rand = underscore()->random(1, 10);
```
times(int $n, callable $fn): selfRun callable n times and create new collection.
```php
$fn = function ($i) { return $i * 2; };underscore()->times(5, $fn)->get();
// [0, 2, 4, 6, 8]
```
uniqueId(string $prefix): stringGenerate unique ID (unique for current go/session).
```php
$u = underscore()->uniqueId(); // '1'
$u1 = underscore()->uniqueId(); // '2'
$u3 = underscore()->uniqueId('id:'); // 'id:3'
```---
### UnderscoreFunction
compose(callable $fn1, callable $fn2, ...callable|null $fn3): mixedReturns a function that is the composition of a list of functions,
each consuming the return value of the function that follows.```php
$c = underscore()->compose('strlen', 'strtolower', 'strtoupper');$c('aBc.xYz'); // ABC.XYZ => abc.xyz => 7
```
delay(callable $fn, int $wait): mixedCache the result of callback for given arguments and reuse that in subsequent call.
```php
$cb = underscore()->delay(function () { echo 'OK'; }, 100);// waits 100ms
$cb(); // 'OK'
```
memoize(callable $fn): mixedReturns a callable which when invoked caches the result for given arguments
and reuses that result in subsequent calls.```php
$sum = underscore()->memoize(function ($a, $b) { return $a + $b; });$sum(4, 5); // 9
// Uses memo:
$sum(4, 5); // 9
```
throttle(callable $fn, int $wait): mixedReturns a callable that wraps given callable which can be only invoked
at most once per given $wait threshold.```php
$fn = underscore()->throttle($callback, 100);while (...) {
$fn(); // it will be constantly called but not executed more than one in 100msif (...) break;
}
```---
### UnderscoreArray
compact(): selfGet only the truthy items.
```php
underscore($array)->compact()->get();
// [1 => 'a', 4 => 2, 5 => [1]
```
difference(array|mixed $data): selfGet the items whose value is not in given data.
```php
underscore([1, 2, 1, 'a' => 3, 'b' => [4]])->difference([1, [4]])->get();
// [1 => 2, 'a' => 3]
```
findIndex(callable $fn): mixed|nullFind the first index that passes given truth test.
```php
$u = underscore([[1, 2], 'a' => 3, 'x' => 4, 'y' => 2, 'b' => 'B']);$isEven = function ($i) { return is_numeric($i) && $i % 2 === 0; };
$u->findIndex(); // 0
$u->findIndex($isEven); // 'x'
```
findLastIndex(callable $fn): mixed|nullFind the last index that passes given truth test.
```php
$u = underscore([[1, 2], 'a' => 3, 'x' => 4, 'y' => 2, 'b' => 'B']);$isEven = function ($i) { return is_numeric($i) && $i % 2 === 0; };
$u->findLastIndex(); // 'b'
$u->findLastIndex($isEven); // 'y'
```
first(int $n): array|mixedGet the first n items.
```php
underscore([1, 2, 3])->first(); // 1
underscore([1, 2, 3])->first(2); // [1, 2]
```
flatten(): selfGets the flattened version of multidimensional items.
```php
$u = underscore([0, 'a', '', [[1, [2]]], 'b', [[[3]], 4, 'c', underscore([5, 'd'])]]);$u->flatten()->get(); // [0, 'a', '', 1, 2, 'b', 3, 4, 'c', 5, 'd']
```
indexOf(mixed $value): string|int|nullFind the first index of given value if available null otherwise.
```php
$u = underscore([[1, 2], 'a' => 2, 'x' => 4]);$array->indexOf(2); // 'a'
```
intersection(array|mixed $data): selfGets the items whose value is common with given data.
```php
$u = underscore([1, 2, 'a' => 3]);$u->intersection([2, 'a' => 3, 3])->get(); // [1 => 2, 'a' => 3]
```
last(int $n): array|mixedGet the last n items.
```php
underscore([1, 2, 3])->last(); // 3
underscore([1, 2, 3])->last(2); // [2, 3]
```
lastIndexOf(mixed $value): string|int|nullFind the last index of given value if available null otherwise.
```php
$u = underscore([[1, 2], 'a' => 2, 'x' => 4, 'y' => 2]);$array->lastIndexOf(2); // 'y'
```
object(string|null $className): selfHydrate the items into given class or stdClass.
```php
underscore(['a', 'b' => 2])->object(); // stdClass(0: 'a', 'b': 2)
```
range(int $start, int $stop, int $step): selfCreates a new range from start to stop with given step.
```php
underscore()->range(4, 9)->get(); // [4, 5, 6, 7, 8, 9]
```
sortedIndex(mixed $object, callable|string $fn): string|int|nullGets the smallest index at which an object should be inserted so as to maintain order.
```php
underscore([1, 3, 5, 8, 11])->sortedIndex(9, null); // 4
```
union(array|mixed $data): selfGet the union/merger of items with given data.
```php
$u = underscore([1, 2, 'a' => 3]);$u->union([3, 'a' => 4, 'b' => [5]])->get(); // [1, 2, 'a' => 4, 3, 'b' => [5]]
```
unique(callable|string $fn): selfGets the unique items using the id resulted from callback.
```php
$u = underscore([1, 2, 'a' => 3]);$u->union([3, 'a' => 4, 'b' => [5]])->get();
// [1, 2, 'a' => 4, 3, 'b' => [5]]
```
zip(array|mixed $data): selfGroup the values from data and items having same indexes together.
```php
$u = underscore([1, 2, 'a' => 3, 'b' => 'B']);$u->zip([2, 4, 'a' => 5])->get();
// [[1, 2], [2, 4], 'a' => [3, 5], 'b' => ['B', null]]
```---
### UnderscoreCollection
contains(mixed $item): boolCheck if the collection contains given item.
```php
$u = underscore(['a' => 1, 'b' => 2, 'c' => 3, 5]);$u->contains(1); // true
$u->contains('x'); // false
```
countBy(callable|string $fn): selfCount items in each group indexed by the result of callback.
```php
$u = underscore([
['a' => 0, 'b' => 1, 'c' => 1],
['a' => true, 'b' => false, 'c' => 'c'],
['a' => 2, 'b' => 1, 'c' => 2],
['a' => 1, 'b' => null, 'c' => 0],
]);// by key 'a'
$u->countBy('a')->get();
// [0 => 1, 1 => 2, 2 => 1]
```
each(callable $fn): selfApply given callback to each of the items in collection.
```php
$answers = [];
underscore([1, 2, 3])->each(function ($num) use (&$answers) {
$answers[] = $num * 5;
});$answers; // [5, 10, 15]
```
every(callable $fn): boolTests if all the items pass given truth test.
```php
$gt0 = underscore([1, 2, 3, 4])->every(function ($num) { return $num > 0; });$gt0; // true
```
filter(callable|string|null $fn): selfFind and return all the items that passes given truth test.
```php
$gt2 = underscore([1, 2, 4, 0, 3])->filter(function ($num) { return $num > 2; });$gt2->values(); // [4, 3]
```
find(callable $fn, bool $useValue): mixed|nullFind the first item (or index) that passes given truth test.
```php
$num = underscore([1, 2, 4, 3])->find(function ($num) { return $num > 2; });$num; // 4
$idx = underscore([1, 2, 4, 3])->find(function ($num) { return $num > 2; }, false);
$idx; // 2
```
findWhere(array $props): mixedGet the first item that contains all the given props (matching both index and value).
```php
$u = underscore([['a' => 1, 'b' => 2], ['a' => 2, 'b' => 2], ['a' => 1, 'b' => 3]]);$u->findWhere(['b' => 3]); // ['a' => 1, 'b' => 3]
```
groupBy(callable|string $fn): selfGroup items by using the result of callback as index. The items in group will have original index intact.
```php
$u = underscore([
['a' => 0, 'b' => 1, 'c' => 1],
['a' => true, 'b' => false, 'c' => 'c'],
['a' => 2, 'b' => 1, 'c' => 2],
['a' => 1, 'b' => null, 'c' => 0],
]);// by key 'a'
$u->groupBy('a')->get();
// [
// 0 => [0 => ['a' => 0, 'b' => 1, 'c' => 1]],
// 1 => [1 => ['a' => true, 'b' => false, 'c' => 'c'], 3 => ['a' => 1, 'b' => null, 'c' => 0]],
// 2 => [2 => ['a' => 2, 'b' => 1, 'c' => 2]],
// ]
```
indexBy(callable|string $fn): selfReindex items by using the result of callback as new index.
```php
$u = underscore([
['a' => 0, 'b' => 1, 'c' => 1],
['a' => true, 'b' => false, 'c' => 'c'],
['a' => 2, 'b' => 1, 'c' => 2],
['a' => 1, 'b' => null, 'c' => 0],
]);// by key 'a'
$u->indexBy('a')->get();
// [
// 0 => ['a' => 0, 'b' => 1, 'c' => 1],
// 1 => ['a' => 1, 'b' => null, 'c' => 0],
// 2 => ['a' => 2, 'b' => 1, 'c' => 2],
// ]
```
invoke(callable $fn): mixedInvoke a callback using all of the items as arguments.
```php
$sum = underscore([1, 2, 4])->invoke(function () { return array_sum(func_get_args()); });$sum; // 7
```
map(callable $fn): selfUpdate the value of each items with the result of given callback.
```php
$map = underscore([1, 2, 3])->map(function ($num) { return $num * 2; });$map->get(); // [2, 4, 6]
```
max(callable|string|null $fn): mixedFind the maximum value using given callback or just items.
```php
underscore([1, 5, 4])->max(); // 5
$u = underscore([['a' => 1, 'b' => 2], ['a' => 2, 'b' => 3], ['a' => 0, 'b' => 1]]);$u->max(function ($i) { return $i['a'] + $i['b']; }); // 5
```
min(callable|string|null $fn): mixedFind the minimum value using given callback or just items.
```php
underscore([1, 5, 4])->min(); // 1
$u = underscore([['a' => 1, 'b' => 2], ['a' => 2, 'b' => 3], ['a' => 0, 'b' => 1]]);$u->min(function ($i) { return $i['a'] + $i['b']; }); // 1
```
partition(callable|string $fn): selfSeparate the items into two groups: one passing given truth test and other failing.
```php
$u = underscore(range(1, 10));$oddEvn = $u->partition(function ($i) { return $i % 2; });
$oddEvn->get(0); // [1, 3, 5, 7, 9]
$oddEvn->get(1); // [2, 4, 6, 8, 10]
```
pluck(string|int $columnKey, string|int $indexKey): selfPluck given property from each of the items.
```php
$u = underscore([['name' => 'moe', 'age' => 30], ['name' => 'curly']]);$u->pluck('name')->get(); // ['moe', 'curly']
```
reduce(callable $fn, mixed $memo): mixedIteratively reduce the array to a single value using a callback function.
```php
$sum = underscore([1, 2, 3])->reduce(function ($sum, $num) {
return $num + $sum;
}, 0);$sum; // 6
```
reduceRight(callable $fn, mixed $memo): mixedSame as reduce but applies the callback from right most item first.
```php
$concat = underscore([1, 2, 3, 4])->reduceRight(function ($concat, $num) {
return $concat . $num;
}, '');echo $concat; // '4321'
```
reject(callable $fn): selfFind and return all the items that fails given truth test.
```php
$evens = underscore([1, 2, 3, 4, 5, 7, 6])->reject(function ($num) {
return $num % 2 !== 0;
});$evens->values(); // [2, 4, 6]
```
sample(int $n): selfGet upto n items in random order.
```php
$u = underscore([1, 2, 3, 4]);$u->sample(1)->count(); // 1
$u->sample(2)->count(); // 2
```
shuffle(): selfRandomize the items keeping the indexes intact.
```php
underscore([1, 2, 3, 4])->shuffle()->get();
```
some(callable $fn): boolTests if some (at least one) of the items pass given truth test.
```php
$some = underscore([1, 2, 0, 4, -1])->some(function ($num) {
return $num > 0;
});$some; // true
```
sortBy(callable $fn): selfSort items by given callback and maintain indexes.
```php
$u = underscore(range(1, 15))->shuffle(); // randomize
$u->sortBy(null)->get(); // [1, 2, ... 15]$u = underscore([['a' => 1, 'b' => 2], ['a' => 2, 'b' => 3], ['a' => 0, 'b' => 1]]);
$u->sortBy('a')->get();
// [2 => ['a' => 0, 'b' => 1], 0 => ['a' => 1, 'b' => 2], 1 => ['a' => 2, 'b' => 3]]$u->sortBy(function ($i) { return $i['a'] + $i['b']; })->get();
// [2 => ['a' => 0, 'b' => 1], 0 => ['a' => 1, 'b' => 2], 1 => ['a' => 2, 'b' => 3]],
```
where(array $props): selfFilter only the items that contain all the given props (matching both index and value).
```php
$u = underscore([['a' => 1, 'b' => 2], ['a' => 2, 'b' => 2], ['a' => 1, 'b' => 3, 'c']]);$u->where(['a' => 1, 'b' => 2])->get(); // [['a' => 1, 'b' => 2, 'c']]
```---
### UnderscoreBase#### `_`(array|mixed $data): self
A static shortcut to constructor.
```php
$u = Ahc\Underscore\Underscore::_([1, 3, 7]);
```#### `__`toString(): string
Stringify the underscore instance as json string.
```php
echo (string) underscore([1, 2, 3]); // [1, 2, 3]
echo (string) underscore(['a', 2, 'c' => 3]); // {0: "a", 1: 2, "c":3}
```
asArray(mixed $data, bool $cast): arrayGet data as array.
```php
underscore()->asArray('one'); // ['one']
underscore()->asArray([1, 2]); // [1, 2]
underscore()->asArray(underscore(['a', 1, 'c', 3])); // ['a', 1, 'c', 3]underscore()->asArray(new class {
public function toArray()
{
return ['a', 'b', 'c'];
}
}); // ['a', 'b', 'c']underscore()->asArray(new class implements \JsonSerializable {
public function jsonSerialize()
{
return ['a' => 1, 'b' => 2, 'c' => 3];
}
}); // ['a' => 1, 'b' => 2, 'c' => 3]
```
clon(): selfCreates a shallow copy of itself.
```php
$u = underscore(['will', 'be', 'cloned']);$u->clon() == $u; // true
$u->clon() === $u; // false
```
count(): intGets the count of items.
```php
underscore([1, 2, [3, 4]])->count(); // 3
underscore()->count(); // 0
```
flat(array $array): arrayFlatten a multi dimension array to 1 dimension.
```php
underscore()->flat([1, 2, [3, 4, [5, 6]]]); // [1, 2, 3, 4, 5, 6]
```
get(string|int|null $index): mixedGet the underlying array data by index.
```php
$u = underscore([1, 2, 3]);$u->get(); // [1, 2, 3]
$u->get(1); // 2
$u->get(3); // 3```
getData(): arrayGet data.
```php
// same as `get()` without args:
underscore([1, 2, 3])->getData(); // [1, 2, 3]
```
getIterator(): \ArrayIteratorGets the iterator for looping.
```php
$it = underscore([1, 2, 3])->getIterator();while ($it->valid()) {
echo $it->current();
}
```
invert(): selfSwap index and value of all the items. The values should be stringifiable.
```php
$u = underscore(['a' => 1, 'b' => 2, 'c' => 3]);$u->invert()->get(); // [1 => 'a', 2 => 'b', 3 => 'c']
```
jsonSerialize(): arrayGets the data for json serialization.
```php
$u = underscore(['a' => 1, 'b' => 2, 'c' => 3]);json_encode($u); // {"a":1,"b":2,"c":3}
```
keys(): selfGet all the keys.
```php
$u = underscore(['a' => 1, 'b' => 2, 'c' => 3, 5]);$u->keys()->get(); // ['a', 'b', 'c', 0]
```
mixin(string $name, \Closure $fn): selfAdds a custom handler/method to instance. The handler is bound to this instance.
```php
Ahc\Underscore\Underscore::mixin('square', function () {
return $this->map(function ($v) { return $v * $v; });
});underscore([1, 2, 3])->square()->get(); // [1, 4, 9]
```
now(): floatThe current time in millisec.
```php
underscore()->now(); // 1529996371081
```
omit(array|...string|...int $index): selfOmit the items having one of the blacklisted indexes.
```php
$u = underscore(['a' => 3, 7, 'b' => 'B', 1 => ['c', 5]]);$u->omit('a', 0)->get(); // ['b' => 'B', 1 => ['c', 5]]
```
pairs(): selfPair all items to use an array of index and value.
```php
$u = ['a' => 3, 7, 'b' => 'B'];$u->pair(); // ['a' => ['a', 3], 0 => [0, 7], 'b' => ['b', 'B']
```
pick(array|...string|...int $index): selfPick only the items having one of the whitelisted indexes.
```php
$u = underscore(['a' => 3, 7, 'b' => 'B', 1 => ['c', 5]]);$u->pick(0, 1)->get(); // [7, 1 => ['c', 5]]
```
tap(callable $fn): selfInvokes callback fn with clone and returns original self.
```php
$u = underscore([1, 2]);$tap = $u->tap(function ($_) { return $_->values(); });
$tap === $u; // true
```
toArray(): arrayConvert the data items to array.
```php
$u = underscore([1, 3, 5, 7]);$u->toArray(); // [1, 3, 5, 7]
```
valueOf(): stringGet string value (JSON representation) of this instance.
```php
underscore(['a', 2, 'c' => 3])->valueOf(); // {0: "a", 1: 2, "c":3}
```
values(): selfGet all the values.
```php
$u = underscore(['a' => 1, 'b' => 2, 'c' => 3, 5]);$u->values()->get(); // [1, 2, 3, 5]
```---
### UnderscoreAliases
collect(callable $fn): selfAlias of map().
detect(callable $fn, bool $useValue): mixed|nullAlias of find().
drop(int $n): array|mixedAlias of last().
foldl(callable $fn, mixed $memo): mixedAlias of reduce().
foldr(callable $fn, mixed $memo): mixedAlias of reduceRight().
head(int $n): array|mixedAlias of first().
includes(): voidAlias of contains().
inject(callable $fn, mixed $memo): mixedAlias of reduce().
select(callable|string|null $fn): selfAlias of filter().
size(): intAlias of count().
tail(int $n): array|mixedAlias of last().
take(int $n): array|mixedAlias of first().
uniq(callable|string $fn): selfAlias of unique().
without(array|mixed $data): selfAlias of difference().
---
### HigherOrderMessageA syntatic sugar to use elegant shorthand oneliner for complex logic often wrapped in closures.
See example below:```php
// Higher Order Messaging
class HOM
{
protected $n;
public $square;public function __construct($n)
{
$this->n = $n;
$this->square = $n * $n;
}public function even()
{
return $this->n % 2 === 0;
}
}$u = [new HOM(1), new HOM(2), new HOM(3), new HOM(4)];
// Filter `even()` items
$evens = $u->filter->even(); // 'even()' method of each items!// Map each evens to their squares
$squares = $evens->map->square; // 'square' prop of each items!
// Gives an Underscore instance// Get the data
$squares->get();
// [1 => 4, 3 => 16]
```Without higher order messaging that would look like:
```php
$evens = $u->filter(function ($it) {
return $it->even();
});$squares = $evens->map(function ($it) {
return $it->square;
});
```---
### \ArrayAccessUnderscore instances can be treated as array:
```php
$u = underscore([1, 2, 'a' => 3]);isset($u['a']); // true
isset($u['b']); // falseecho $u[1]; // 2
$u['b'] = 'B';
isset($u['b']); // trueunset($u[1]);
```---
### ArrayizesYou can use this trait to arrayize all complex data.
```php
use Ahc\Underscore\Arrayizes;class Any
{
use Arrayizes;public function name()
{
$this->asArray($data);
}
}
```---
#### License> [MIT](./LICENSE) | © 2017-2018 | Jitendra Adhikari