{"id":15355063,"url":"https://github.com/adhocore/php-underscore","last_synced_at":"2025-09-02T23:33:25.857Z","repository":{"id":49147965,"uuid":"108437038","full_name":"adhocore/php-underscore","owner":"adhocore","description":"PHP underscore inspired \u0026/or cloned from _.js, with extra goodies like higher order messaging","archived":false,"fork":false,"pushed_at":"2023-03-25T14:30:34.000Z","size":117,"stargazers_count":44,"open_issues_count":0,"forks_count":6,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-05-15T03:51:16.431Z","etag":null,"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"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/adhocore.png","metadata":{"files":{"readme":"readme.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"adhocore","custom":["https://paypal.me/ji10"]}},"created_at":"2017-10-26T16:27:47.000Z","updated_at":"2023-06-19T06:10:08.000Z","dependencies_parsed_at":"2025-04-16T02:01:33.221Z","dependency_job_id":null,"html_url":"https://github.com/adhocore/php-underscore","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/adhocore/php-underscore","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adhocore%2Fphp-underscore","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adhocore%2Fphp-underscore/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adhocore%2Fphp-underscore/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adhocore%2Fphp-underscore/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/adhocore","download_url":"https://codeload.github.com/adhocore/php-underscore/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adhocore%2Fphp-underscore/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261073293,"owners_count":23105637,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["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"],"created_at":"2024-10-01T12:22:21.036Z","updated_at":"2025-06-21T06:03:27.687Z","avatar_url":"https://github.com/adhocore.png","language":"PHP","readme":"## adhocore/underscore\n\nPHP underscore inspired \u0026amp;/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.\n\n[![Latest Version](https://img.shields.io/github/release/adhocore/php-underscore.svg?style=flat-square)](https://github.com/adhocore/php-underscore/releases)\n[![Travis Build](https://img.shields.io/travis/adhocore/php-underscore/master.svg?style=flat-square)](https://travis-ci.org/adhocore/php-underscore?branch=master)\n[![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)\n[![Codecov branch](https://img.shields.io/codecov/c/github/adhocore/php-underscore/master.svg?style=flat-square)](https://codecov.io/gh/adhocore/php-underscore)\n[![StyleCI](https://styleci.io/repos/108437038/shield)](https://styleci.io/repos/108437038)\n[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE)\n[![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\u0026url=https://github.com/adhocore/php-underscore\u0026hashtags=php,functional,array,collection)\n[![Support](https://img.shields.io/static/v1?label=Support\u0026message=%E2%9D%A4\u0026logo=GitHub)](https://github.com/sponsors/adhocore)\n\u003c!-- [![Donate 15](https://img.shields.io/badge/donate-paypal-blue.svg?style=flat-square\u0026label=donate+15)](https://www.paypal.me/ji10/15usd)\n[![Donate 25](https://img.shields.io/badge/donate-paypal-blue.svg?style=flat-square\u0026label=donate+25)](https://www.paypal.me/ji10/25usd)\n[![Donate 50](https://img.shields.io/badge/donate-paypal-blue.svg?style=flat-square\u0026label=donate+50)](https://www.paypal.me/ji10/50usd) --\u003e\n\n\n- Zero dependency (no vendor bloat).\n\n## Installation\n\nRequires PHP5.6 or later.\n\n```sh\ncomposer require adhocore/underscore\n```\n\n## Usage and API\n\nAlthough all of them are available with helper function `underscore($data)` or `new Ahc\\Underscore($data)`,\nthe methods are grouped and organized in different heriarchy and classes according as their scope.\nThis keeps it maintainable and saves from having a God class.\n\n#### Contents\n\n- [Underscore](#underscore)\n- [UnderscoreFunction](#underscorefunction)\n- [UnderscoreArray](#underscorearray)\n- [UnderscoreCollection](#underscorecollection)\n- [UnderscoreBase](#underscorebase)\n- [HigherOrderMessage](#higherordermessage)\n- [ArrayAccess](#arrayaccess)\n- [Arrayizes](#arrayizes)\n\n\n---\n### Underscore\n\n\u003ch4\u003e\u003ca name=\"constant\"\u003e\u003c/a\u003econstant(mixed $value): callable\u003c/h4\u003e\n\nGenerates a function that always returns a constant value.\n\n```php\n$fn = underscore()-\u003econstant([1, 2]);\n\n$fn(); // [1, 2]\n```\n\n\u003ch4\u003e\u003ca name=\"noop\"\u003e\u003c/a\u003enoop(): void\u003c/h4\u003e\n\nNo operation!\n```php\nunderscore()-\u003enoop(); // void/null\n```\n\n\u003ch4\u003e\u003ca name=\"random\"\u003e\u003c/a\u003erandom(int $min, int $max): int\u003c/h4\u003e\n\nReturn a random integer between min and max (inclusive).\n\n```php\n$rand = underscore()-\u003erandom(1, 10);\n```\n\n\u003ch4\u003e\u003ca name=\"times\"\u003e\u003c/a\u003etimes(int $n, callable $fn): self\u003c/h4\u003e\n\nRun callable n times and create new collection.\n\n```php\n$fn = function ($i) { return $i * 2; };\n\nunderscore()-\u003etimes(5, $fn)-\u003eget();\n// [0, 2, 4, 6, 8]\n```\n\n\u003ch4\u003e\u003ca name=\"uniqueId\"\u003e\u003c/a\u003euniqueId(string $prefix): string\u003c/h4\u003e\n\nGenerate unique ID (unique for current go/session).\n\n```php\n$u  = underscore()-\u003euniqueId();      // '1'\n$u1 = underscore()-\u003euniqueId();      // '2'\n$u3 = underscore()-\u003euniqueId('id:'); // 'id:3'\n```\n\n\n---\n### UnderscoreFunction\n\n\u003ch4\u003e\u003ca name=\"compose\"\u003e\u003c/a\u003ecompose(callable $fn1, callable $fn2, ...callable|null $fn3): mixed\u003c/h4\u003e\n\nReturns a function that is the composition of a list of functions,\neach consuming the return value of the function that follows.\n\n```php\n$c = underscore()-\u003ecompose('strlen', 'strtolower', 'strtoupper');\n\n$c('aBc.xYz'); // ABC.XYZ =\u003e abc.xyz =\u003e 7\n```\n\n\u003ch4\u003e\u003ca name=\"delay\"\u003e\u003c/a\u003edelay(callable $fn, int $wait): mixed\u003c/h4\u003e\n\nCache the result of callback for given arguments and reuse that in subsequent call.\n\n```php\n$cb = underscore()-\u003edelay(function () { echo 'OK'; }, 100);\n\n// waits 100ms\n$cb(); // 'OK'\n```\n\n\u003ch4\u003e\u003ca name=\"memoize\"\u003e\u003c/a\u003ememoize(callable $fn): mixed\u003c/h4\u003e\n\nReturns a callable which when invoked caches the result for given arguments\nand reuses that result in subsequent calls.\n\n```php\n$sum = underscore()-\u003ememoize(function ($a, $b) { return $a + $b; });\n\n$sum(4, 5); // 9\n\n// Uses memo:\n$sum(4, 5); // 9\n```\n\n\u003ch4\u003e\u003ca name=\"throttle\"\u003e\u003c/a\u003ethrottle(callable $fn, int $wait): mixed\u003c/h4\u003e\n\nReturns a callable that wraps given callable which can be only invoked\nat most once per given $wait threshold.\n\n```php\n$fn = underscore()-\u003ethrottle($callback, 100);\n\nwhile (...) {\n    $fn(); // it will be constantly called but not executed more than one in 100ms\n\n    if (...) break;\n}\n```\n\n\n---\n### UnderscoreArray\n\n\u003ch4\u003e\u003ca name=\"compact\"\u003e\u003c/a\u003ecompact(): self\u003c/h4\u003e\n\nGet only the truthy items.\n\n```php\nunderscore($array)-\u003ecompact()-\u003eget();\n// [1 =\u003e 'a', 4 =\u003e 2, 5 =\u003e [1]\n```\n\n\u003ch4\u003e\u003ca name=\"difference\"\u003e\u003c/a\u003edifference(array|mixed $data): self\u003c/h4\u003e\n\nGet the items whose value is not in given data.\n\n```php\nunderscore([1, 2, 1, 'a' =\u003e 3, 'b' =\u003e [4]])-\u003edifference([1, [4]])-\u003eget();\n// [1 =\u003e 2, 'a' =\u003e 3]\n```\n\n\u003ch4\u003e\u003ca name=\"findIndex\"\u003e\u003c/a\u003efindIndex(callable $fn): mixed|null\u003c/h4\u003e\n\nFind the first index that passes given truth test.\n\n```php\n$u = underscore([[1, 2], 'a' =\u003e 3, 'x' =\u003e 4, 'y' =\u003e 2, 'b' =\u003e 'B']);\n\n$isEven = function ($i) { return is_numeric($i) \u0026\u0026 $i % 2 === 0; };\n\n$u-\u003efindIndex();        // 0\n$u-\u003efindIndex($isEven); // 'x'\n```\n\n\u003ch4\u003e\u003ca name=\"findLastIndex\"\u003e\u003c/a\u003efindLastIndex(callable $fn): mixed|null\u003c/h4\u003e\n\nFind the last index that passes given truth test.\n\n```php\n$u = underscore([[1, 2], 'a' =\u003e 3, 'x' =\u003e 4, 'y' =\u003e 2, 'b' =\u003e 'B']);\n\n$isEven = function ($i) { return is_numeric($i) \u0026\u0026 $i % 2 === 0; };\n\n$u-\u003efindLastIndex();        // 'b'\n$u-\u003efindLastIndex($isEven); // 'y'\n```\n\n\u003ch4\u003e\u003ca name=\"first\"\u003e\u003c/a\u003efirst(int $n): array|mixed\u003c/h4\u003e\n\nGet the first n items.\n\n```php\nunderscore([1, 2, 3])-\u003efirst(); // 1\nunderscore([1, 2, 3])-\u003efirst(2); // [1, 2]\n```\n\n\u003ch4\u003e\u003ca name=\"flatten\"\u003e\u003c/a\u003eflatten(): self\u003c/h4\u003e\n\nGets the flattened version of multidimensional items.\n\n```php\n$u = underscore([0, 'a', '', [[1, [2]]], 'b', [[[3]], 4, 'c', underscore([5, 'd'])]]);\n\n$u-\u003eflatten()-\u003eget(); // [0, 'a', '', 1, 2, 'b', 3, 4, 'c', 5, 'd']\n```\n\n\u003ch4\u003e\u003ca name=\"indexOf\"\u003e\u003c/a\u003eindexOf(mixed $value): string|int|null\u003c/h4\u003e\n\nFind the first index of given value if available null otherwise.\n\n```php\n$u = underscore([[1, 2], 'a' =\u003e 2, 'x' =\u003e 4]);\n\n$array-\u003eindexOf(2); // 'a'\n```\n\n\u003ch4\u003e\u003ca name=\"intersection\"\u003e\u003c/a\u003eintersection(array|mixed $data): self\u003c/h4\u003e\n\nGets the items whose value is common with given data.\n\n```php\n$u = underscore([1, 2, 'a' =\u003e 3]);\n\n$u-\u003eintersection([2, 'a' =\u003e 3, 3])-\u003eget(); // [1 =\u003e 2, 'a' =\u003e 3]\n```\n\n\u003ch4\u003e\u003ca name=\"last\"\u003e\u003c/a\u003elast(int $n): array|mixed\u003c/h4\u003e\n\nGet the last n items.\n\n```php\nunderscore([1, 2, 3])-\u003elast();   // 3\nunderscore([1, 2, 3])-\u003elast(2);  // [2, 3]\n```\n\n\u003ch4\u003e\u003ca name=\"lastIndexOf\"\u003e\u003c/a\u003elastIndexOf(mixed $value): string|int|null\u003c/h4\u003e\n\nFind the last index of given value if available null otherwise.\n\n```php\n$u = underscore([[1, 2], 'a' =\u003e 2, 'x' =\u003e 4, 'y' =\u003e 2]);\n\n$array-\u003elastIndexOf(2); // 'y'\n```\n\n\u003ch4\u003e\u003ca name=\"object\"\u003e\u003c/a\u003eobject(string|null $className): self\u003c/h4\u003e\n\nHydrate the items into given class or stdClass.\n\n```php\nunderscore(['a', 'b' =\u003e 2])-\u003eobject(); // stdClass(0: 'a', 'b': 2)\n```\n\n\u003ch4\u003e\u003ca name=\"range\"\u003e\u003c/a\u003erange(int $start, int $stop, int $step): self\u003c/h4\u003e\n\nCreates a new range from start to stop with given step.\n\n```php\nunderscore()-\u003erange(4, 9)-\u003eget(); // [4, 5, 6, 7, 8, 9]\n```\n\n\u003ch4\u003e\u003ca name=\"sortedIndex\"\u003e\u003c/a\u003esortedIndex(mixed $object, callable|string $fn): string|int|null\u003c/h4\u003e\n\nGets the smallest index at which an object should be inserted so as to maintain order.\n\n```php\nunderscore([1, 3, 5, 8, 11])-\u003esortedIndex(9, null); // 4\n```\n\n\u003ch4\u003e\u003ca name=\"union\"\u003e\u003c/a\u003eunion(array|mixed $data): self\u003c/h4\u003e\n\nGet the union/merger of items with given data.\n\n```php\n$u = underscore([1, 2, 'a' =\u003e 3]);\n\n$u-\u003eunion([3, 'a' =\u003e 4, 'b' =\u003e [5]])-\u003eget(); // [1, 2, 'a' =\u003e 4, 3, 'b' =\u003e [5]]\n```\n\n\u003ch4\u003e\u003ca name=\"unique\"\u003e\u003c/a\u003eunique(callable|string $fn): self\u003c/h4\u003e\n\nGets the unique items using the id resulted from callback.\n\n```php\n$u = underscore([1, 2, 'a' =\u003e 3]);\n\n$u-\u003eunion([3, 'a' =\u003e 4, 'b' =\u003e [5]])-\u003eget();\n// [1, 2, 'a' =\u003e 4, 3, 'b' =\u003e [5]]\n```\n\n\u003ch4\u003e\u003ca name=\"zip\"\u003e\u003c/a\u003ezip(array|mixed $data): self\u003c/h4\u003e\n\nGroup the values from data and items having same indexes together.\n\n```php\n$u = underscore([1, 2, 'a' =\u003e 3, 'b' =\u003e 'B']);\n\n$u-\u003ezip([2, 4, 'a' =\u003e 5])-\u003eget();\n// [[1, 2], [2, 4], 'a' =\u003e [3, 5], 'b' =\u003e ['B', null]]\n```\n\n\n---\n### UnderscoreCollection\n\n\u003ch4\u003e\u003ca name=\"contains\"\u003e\u003c/a\u003econtains(mixed $item): bool\u003c/h4\u003e\n\nCheck if the collection contains given item.\n\n```php\n$u = underscore(['a' =\u003e 1, 'b' =\u003e 2, 'c' =\u003e 3, 5]);\n\n$u-\u003econtains(1);   // true\n$u-\u003econtains('x'); // false\n```\n\n\u003ch4\u003e\u003ca name=\"countBy\"\u003e\u003c/a\u003ecountBy(callable|string $fn): self\u003c/h4\u003e\n\nCount items in each group indexed by the result of callback.\n\n```php\n$u = underscore([\n    ['a' =\u003e 0, 'b' =\u003e 1, 'c' =\u003e 1],\n    ['a' =\u003e true, 'b' =\u003e false, 'c' =\u003e 'c'],\n    ['a' =\u003e 2, 'b' =\u003e 1, 'c' =\u003e 2],\n    ['a' =\u003e 1, 'b' =\u003e null, 'c' =\u003e 0],\n]);\n\n// by key 'a'\n$u-\u003ecountBy('a')-\u003eget();\n// [0 =\u003e 1, 1 =\u003e 2, 2 =\u003e 1]\n```\n\n\u003ch4\u003e\u003ca name=\"each\"\u003e\u003c/a\u003eeach(callable $fn): self\u003c/h4\u003e\n\nApply given callback to each of the items in collection.\n\n```php\n$answers = [];\nunderscore([1, 2, 3])-\u003eeach(function ($num) use (\u0026$answers) {\n    $answers[] = $num * 5;\n});\n\n$answers; // [5, 10, 15]\n```\n\n\u003ch4\u003e\u003ca name=\"every\"\u003e\u003c/a\u003eevery(callable $fn): bool\u003c/h4\u003e\n\nTests if all the items pass given truth test.\n\n```php\n$gt0 = underscore([1, 2, 3, 4])-\u003eevery(function ($num) { return $num \u003e 0; });\n\n$gt0; // true\n```\n\n\u003ch4\u003e\u003ca name=\"filter\"\u003e\u003c/a\u003efilter(callable|string|null $fn): self\u003c/h4\u003e\n\nFind and return all the items that passes given truth test.\n\n```php\n$gt2 = underscore([1, 2, 4, 0, 3])-\u003efilter(function ($num) { return $num \u003e 2; });\n\n$gt2-\u003evalues(); // [4, 3]\n```\n\n\u003ch4\u003e\u003ca name=\"find\"\u003e\u003c/a\u003efind(callable $fn, bool $useValue): mixed|null\u003c/h4\u003e\n\nFind the first item (or index) that passes given truth test.\n\n```php\n$num = underscore([1, 2, 4, 3])-\u003efind(function ($num) { return $num \u003e 2; });\n\n$num; // 4\n\n$idx = underscore([1, 2, 4, 3])-\u003efind(function ($num) { return $num \u003e 2; }, false);\n\n$idx; // 2\n```\n\n\u003ch4\u003e\u003ca name=\"findWhere\"\u003e\u003c/a\u003efindWhere(array $props): mixed\u003c/h4\u003e\n\nGet the first item that contains all the given props (matching both index and value).\n\n```php\n$u = underscore([['a' =\u003e 1, 'b' =\u003e 2], ['a' =\u003e 2, 'b' =\u003e 2], ['a' =\u003e 1, 'b' =\u003e 3]]);\n\n$u-\u003efindWhere(['b' =\u003e 3]); // ['a' =\u003e 1, 'b' =\u003e 3]\n```\n\n\u003ch4\u003e\u003ca name=\"groupBy\"\u003e\u003c/a\u003egroupBy(callable|string $fn): self\u003c/h4\u003e\n\nGroup items by using the result of callback as index. The items in group will have original index intact.\n\n```php\n$u = underscore([\n    ['a' =\u003e 0, 'b' =\u003e 1, 'c' =\u003e 1],\n    ['a' =\u003e true, 'b' =\u003e false, 'c' =\u003e 'c'],\n    ['a' =\u003e 2, 'b' =\u003e 1, 'c' =\u003e 2],\n    ['a' =\u003e 1, 'b' =\u003e null, 'c' =\u003e 0],\n]);\n\n// by key 'a'\n$u-\u003egroupBy('a')-\u003eget();\n// [\n//  0 =\u003e [0 =\u003e ['a' =\u003e 0, 'b' =\u003e 1, 'c' =\u003e 1]],\n//  1 =\u003e [1 =\u003e ['a' =\u003e true, 'b' =\u003e false, 'c' =\u003e 'c'], 3 =\u003e ['a' =\u003e 1, 'b' =\u003e null, 'c' =\u003e 0]],\n//  2 =\u003e [2 =\u003e ['a' =\u003e 2, 'b' =\u003e 1, 'c' =\u003e 2]],\n// ]\n```\n\n\u003ch4\u003e\u003ca name=\"indexBy\"\u003e\u003c/a\u003eindexBy(callable|string $fn): self\u003c/h4\u003e\n\nReindex items by using the result of callback as new index.\n\n```php\n$u = underscore([\n    ['a' =\u003e 0, 'b' =\u003e 1, 'c' =\u003e 1],\n    ['a' =\u003e true, 'b' =\u003e false, 'c' =\u003e 'c'],\n    ['a' =\u003e 2, 'b' =\u003e 1, 'c' =\u003e 2],\n    ['a' =\u003e 1, 'b' =\u003e null, 'c' =\u003e 0],\n]);\n\n// by key 'a'\n$u-\u003eindexBy('a')-\u003eget();\n// [\n//   0 =\u003e ['a' =\u003e 0, 'b' =\u003e 1, 'c' =\u003e 1],\n//   1 =\u003e ['a' =\u003e 1, 'b' =\u003e null, 'c' =\u003e 0],\n//   2 =\u003e ['a' =\u003e 2, 'b' =\u003e 1, 'c' =\u003e 2],\n// ]\n```\n\n\u003ch4\u003e\u003ca name=\"invoke\"\u003e\u003c/a\u003einvoke(callable $fn): mixed\u003c/h4\u003e\n\nInvoke a callback using all of the items as arguments.\n\n```php\n$sum = underscore([1, 2, 4])-\u003einvoke(function () { return array_sum(func_get_args()); });\n\n$sum; // 7\n```\n\n\u003ch4\u003e\u003ca name=\"map\"\u003e\u003c/a\u003emap(callable $fn): self\u003c/h4\u003e\n\nUpdate the value of each items with the result of given callback.\n\n```php\n$map = underscore([1, 2, 3])-\u003emap(function ($num) { return $num * 2; });\n\n$map-\u003eget(); // [2, 4, 6]\n```\n\n\u003ch4\u003e\u003ca name=\"max\"\u003e\u003c/a\u003emax(callable|string|null $fn): mixed\u003c/h4\u003e\n\nFind the maximum value using given callback or just items.\n\n```php\nunderscore([1, 5, 4])-\u003emax(); // 5\n$u = underscore([['a' =\u003e 1, 'b' =\u003e 2], ['a' =\u003e 2, 'b' =\u003e 3], ['a' =\u003e 0, 'b' =\u003e 1]]);\n\n$u-\u003emax(function ($i) { return $i['a'] + $i['b']; }); // 5\n```\n\n\u003ch4\u003e\u003ca name=\"min\"\u003e\u003c/a\u003emin(callable|string|null $fn): mixed\u003c/h4\u003e\n\nFind the minimum value using given callback or just items.\n\n```php\nunderscore([1, 5, 4])-\u003emin(); // 1\n$u = underscore([['a' =\u003e 1, 'b' =\u003e 2], ['a' =\u003e 2, 'b' =\u003e 3], ['a' =\u003e 0, 'b' =\u003e 1]]);\n\n$u-\u003emin(function ($i) { return $i['a'] + $i['b']; }); // 1\n```\n\n\u003ch4\u003e\u003ca name=\"partition\"\u003e\u003c/a\u003epartition(callable|string $fn): self\u003c/h4\u003e\n\nSeparate the items into two groups: one passing given truth test and other failing.\n\n```php\n$u = underscore(range(1, 10));\n\n$oddEvn = $u-\u003epartition(function ($i) { return $i % 2; });\n\n$oddEvn-\u003eget(0); // [1, 3, 5, 7, 9]\n$oddEvn-\u003eget(1); // [2, 4, 6, 8, 10]\n```\n\n\u003ch4\u003e\u003ca name=\"pluck\"\u003e\u003c/a\u003epluck(string|int $columnKey, string|int $indexKey): self\u003c/h4\u003e\n\nPluck given property from each of the items.\n\n```php\n$u = underscore([['name' =\u003e 'moe', 'age' =\u003e 30], ['name' =\u003e 'curly']]);\n\n$u-\u003epluck('name')-\u003eget(); // ['moe', 'curly']\n```\n\n\u003ch4\u003e\u003ca name=\"reduce\"\u003e\u003c/a\u003ereduce(callable $fn, mixed $memo): mixed\u003c/h4\u003e\n\nIteratively reduce the array to a single value using a callback function.\n\n```php\n$sum = underscore([1, 2, 3])-\u003ereduce(function ($sum, $num) {\n    return $num + $sum;\n}, 0);\n\n$sum; // 6\n```\n\n\u003ch4\u003e\u003ca name=\"reduceRight\"\u003e\u003c/a\u003ereduceRight(callable $fn, mixed $memo): mixed\u003c/h4\u003e\n\nSame as reduce but applies the callback from right most item first.\n\n```php\n$concat = underscore([1, 2, 3, 4])-\u003ereduceRight(function ($concat, $num) {\n    return $concat . $num;\n}, '');\n\necho $concat; // '4321'\n```\n\n\u003ch4\u003e\u003ca name=\"reject\"\u003e\u003c/a\u003ereject(callable $fn): self\u003c/h4\u003e\n\nFind and return all the items that fails given truth test.\n\n```php\n$evens = underscore([1, 2, 3, 4, 5, 7, 6])-\u003ereject(function ($num) {\n    return $num % 2 !== 0;\n});\n\n$evens-\u003evalues(); // [2, 4, 6]\n```\n\n\u003ch4\u003e\u003ca name=\"sample\"\u003e\u003c/a\u003esample(int $n): self\u003c/h4\u003e\n\nGet upto n items in random order.\n\n```php\n$u = underscore([1, 2, 3, 4]);\n\n$u-\u003esample(1)-\u003ecount(); // 1\n$u-\u003esample(2)-\u003ecount(); // 2\n```\n\n\u003ch4\u003e\u003ca name=\"shuffle\"\u003e\u003c/a\u003eshuffle(): self\u003c/h4\u003e\n\nRandomize the items keeping the indexes intact.\n\n```php\nunderscore([1, 2, 3, 4])-\u003eshuffle()-\u003eget();\n```\n\n\u003ch4\u003e\u003ca name=\"some\"\u003e\u003c/a\u003esome(callable $fn): bool\u003c/h4\u003e\n\nTests if some (at least one) of the items pass given truth test.\n\n```php\n$some = underscore([1, 2, 0, 4, -1])-\u003esome(function ($num) {\n    return $num \u003e 0;\n});\n\n$some; // true\n```\n\n\u003ch4\u003e\u003ca name=\"sortBy\"\u003e\u003c/a\u003esortBy(callable $fn): self\u003c/h4\u003e\n\nSort items by given callback and maintain indexes.\n\n```php\n$u = underscore(range(1, 15))-\u003eshuffle(); // randomize\n$u-\u003esortBy(null)-\u003eget(); // [1, 2, ... 15]\n\n$u = underscore([['a' =\u003e 1, 'b' =\u003e 2], ['a' =\u003e 2, 'b' =\u003e 3], ['a' =\u003e 0, 'b' =\u003e 1]]);\n$u-\u003esortBy('a')-\u003eget();\n// [2 =\u003e ['a' =\u003e 0, 'b' =\u003e 1], 0 =\u003e ['a' =\u003e 1, 'b' =\u003e 2], 1 =\u003e ['a' =\u003e 2, 'b' =\u003e 3]]\n\n$u-\u003esortBy(function ($i) { return $i['a'] + $i['b']; })-\u003eget();\n// [2 =\u003e ['a' =\u003e 0, 'b' =\u003e 1], 0 =\u003e ['a' =\u003e 1, 'b' =\u003e 2], 1 =\u003e ['a' =\u003e 2, 'b' =\u003e 3]],\n```\n\n\u003ch4\u003e\u003ca name=\"where\"\u003e\u003c/a\u003ewhere(array $props): self\u003c/h4\u003e\n\nFilter only the items that contain all the given props (matching both index and value).\n\n```php\n$u = underscore([['a' =\u003e 1, 'b' =\u003e 2], ['a' =\u003e 2, 'b' =\u003e 2], ['a' =\u003e 1, 'b' =\u003e 3, 'c']]);\n\n$u-\u003ewhere(['a' =\u003e 1, 'b' =\u003e 2])-\u003eget(); // [['a' =\u003e 1, 'b' =\u003e 2, 'c']]\n```\n\n\n---\n### UnderscoreBase\n\n#### `_`(array|mixed $data): self\n\nA static shortcut to constructor.\n\n```php\n$u = Ahc\\Underscore\\Underscore::_([1, 3, 7]);\n```\n\n#### `__`toString(): string\n\nStringify the underscore instance as json string.\n\n```php\necho (string) underscore([1, 2, 3]); // [1, 2, 3]\necho (string) underscore(['a', 2, 'c' =\u003e 3]); // {0: \"a\", 1: 2, \"c\":3}\n```\n\n\u003ch4\u003e\u003ca name=\"asArray\"\u003e\u003c/a\u003easArray(mixed $data, bool $cast): array\u003c/h4\u003e\n\nGet data as array.\n\n```php\nunderscore()-\u003easArray('one');                        // ['one']\nunderscore()-\u003easArray([1, 2]);                       // [1, 2]\nunderscore()-\u003easArray(underscore(['a', 1, 'c', 3])); // ['a', 1, 'c', 3]\n\nunderscore()-\u003easArray(new class {\n    public function toArray()\n    {\n        return ['a', 'b', 'c'];\n    }\n}); // ['a', 'b', 'c']\n\nunderscore()-\u003easArray(new class implements \\JsonSerializable {\n    public function jsonSerialize()\n    {\n        return ['a' =\u003e 1, 'b' =\u003e 2, 'c' =\u003e 3];\n    }\n}); // ['a' =\u003e 1, 'b' =\u003e 2, 'c' =\u003e 3]\n```\n\n\u003ch4\u003e\u003ca name=\"clon\"\u003e\u003c/a\u003eclon(): self\u003c/h4\u003e\n\nCreates a shallow copy of itself.\n\n```php\n$u = underscore(['will', 'be', 'cloned']);\n\n$u-\u003eclon() ==  $u; // true\n$u-\u003eclon() === $u; // false\n```\n\n\u003ch4\u003e\u003ca name=\"count\"\u003e\u003c/a\u003ecount(): int\u003c/h4\u003e\n\nGets the count of items.\n\n```php\nunderscore([1, 2, [3, 4]])-\u003ecount(); // 3\nunderscore()-\u003ecount();               // 0\n```\n\n\u003ch4\u003e\u003ca name=\"flat\"\u003e\u003c/a\u003eflat(array $array): array\u003c/h4\u003e\n\nFlatten a multi dimension array to 1 dimension.\n\n```php\nunderscore()-\u003eflat([1, 2, [3, 4, [5, 6]]]); // [1, 2, 3, 4, 5, 6]\n```\n\n\u003ch4\u003e\u003ca name=\"get\"\u003e\u003c/a\u003eget(string|int|null $index): mixed\u003c/h4\u003e\n\nGet the underlying array data by index.\n\n```php\n$u = underscore([1, 2, 3]);\n\n$u-\u003eget();  // [1, 2, 3]\n$u-\u003eget(1); // 2\n$u-\u003eget(3); // 3\n\n```\n\n\u003ch4\u003e\u003ca name=\"getData\"\u003e\u003c/a\u003egetData(): array\u003c/h4\u003e\n\nGet data.\n\n```php\n// same as `get()` without args:\nunderscore([1, 2, 3])-\u003egetData(); // [1, 2, 3]\n```\n\n\u003ch4\u003e\u003ca name=\"getIterator\"\u003e\u003c/a\u003egetIterator(): \\ArrayIterator\u003c/h4\u003e\n\nGets the iterator for looping.\n\n```php\n$it = underscore([1, 2, 3])-\u003egetIterator();\n\nwhile ($it-\u003evalid()) {\n    echo $it-\u003ecurrent();\n}\n```\n\n\u003ch4\u003e\u003ca name=\"invert\"\u003e\u003c/a\u003einvert(): self\u003c/h4\u003e\n\nSwap index and value of all the items. The values should be stringifiable.\n\n```php\n$u = underscore(['a' =\u003e 1, 'b' =\u003e 2, 'c' =\u003e 3]);\n\n$u-\u003einvert()-\u003eget(); // [1 =\u003e 'a', 2 =\u003e 'b', 3 =\u003e 'c']\n```\n\n\u003ch4\u003e\u003ca name=\"jsonSerialize\"\u003e\u003c/a\u003ejsonSerialize(): array\u003c/h4\u003e\n\nGets the data for json serialization.\n\n```php\n$u = underscore(['a' =\u003e 1, 'b' =\u003e 2, 'c' =\u003e 3]);\n\njson_encode($u); // {\"a\":1,\"b\":2,\"c\":3}\n```\n\n\u003ch4\u003e\u003ca name=\"keys\"\u003e\u003c/a\u003ekeys(): self\u003c/h4\u003e\n\nGet all the keys.\n\n```php\n$u = underscore(['a' =\u003e 1, 'b' =\u003e 2, 'c' =\u003e 3, 5]);\n\n$u-\u003ekeys()-\u003eget(); // ['a', 'b', 'c', 0]\n```\n\n\u003ch4\u003e\u003ca name=\"mixin\"\u003e\u003c/a\u003emixin(string $name, \\Closure $fn): self\u003c/h4\u003e\n\nAdds a custom handler/method to instance. The handler is bound to this instance.\n\n```php\nAhc\\Underscore\\Underscore::mixin('square', function () {\n    return $this-\u003emap(function ($v) { return $v * $v; });\n});\n\nunderscore([1, 2, 3])-\u003esquare()-\u003eget(); // [1, 4, 9]\n```\n\n\u003ch4\u003e\u003ca name=\"now\"\u003e\u003c/a\u003enow(): float\u003c/h4\u003e\n\nThe current time in millisec.\n\n```php\nunderscore()-\u003enow(); // 1529996371081\n```\n\n\u003ch4\u003e\u003ca name=\"omit\"\u003e\u003c/a\u003eomit(array|...string|...int $index): self\u003c/h4\u003e\n\nOmit the items having one of the blacklisted indexes.\n\n```php\n$u = underscore(['a' =\u003e 3, 7, 'b' =\u003e 'B', 1 =\u003e ['c', 5]]);\n\n$u-\u003eomit('a', 0)-\u003eget(); // ['b' =\u003e 'B', 1 =\u003e ['c', 5]]\n```\n\n\u003ch4\u003e\u003ca name=\"pairs\"\u003e\u003c/a\u003epairs(): self\u003c/h4\u003e\n\nPair all items to use an array of index and value.\n\n```php\n$u = ['a' =\u003e 3, 7, 'b' =\u003e 'B'];\n\n$u-\u003epair(); // ['a' =\u003e ['a', 3], 0 =\u003e [0, 7], 'b' =\u003e ['b', 'B']\n```\n\n\u003ch4\u003e\u003ca name=\"pick\"\u003e\u003c/a\u003epick(array|...string|...int $index): self\u003c/h4\u003e\n\nPick only the items having one of the whitelisted indexes.\n\n```php\n$u = underscore(['a' =\u003e 3, 7, 'b' =\u003e 'B', 1 =\u003e ['c', 5]]);\n\n$u-\u003epick(0, 1)-\u003eget(); // [7, 1 =\u003e ['c', 5]]\n```\n\n\u003ch4\u003e\u003ca name=\"tap\"\u003e\u003c/a\u003etap(callable $fn): self\u003c/h4\u003e\n\nInvokes callback fn with clone and returns original self.\n\n```php\n$u = underscore([1, 2]);\n\n$tap = $u-\u003etap(function ($_) { return $_-\u003evalues(); });\n\n$tap === $u; // true\n```\n\n\u003ch4\u003e\u003ca name=\"toArray\"\u003e\u003c/a\u003etoArray(): array\u003c/h4\u003e\n\nConvert the data items to array.\n\n```php\n$u = underscore([1, 3, 5, 7]);\n\n$u-\u003etoArray(); // [1, 3, 5, 7]\n```\n\n\u003ch4\u003e\u003ca name=\"valueOf\"\u003e\u003c/a\u003evalueOf(): string\u003c/h4\u003e\n\nGet string value (JSON representation) of this instance.\n\n```php\nunderscore(['a', 2, 'c' =\u003e 3])-\u003evalueOf(); // {0: \"a\", 1: 2, \"c\":3}\n```\n\n\u003ch4\u003e\u003ca name=\"values\"\u003e\u003c/a\u003evalues(): self\u003c/h4\u003e\n\nGet all the values.\n\n```php\n$u = underscore(['a' =\u003e 1, 'b' =\u003e 2, 'c' =\u003e 3, 5]);\n\n$u-\u003evalues()-\u003eget(); // [1, 2, 3, 5]\n```\n\n\n---\n### UnderscoreAliases\n\n\u003ch4\u003e\u003ca name=\"collect\"\u003e\u003c/a\u003ecollect(callable $fn): self\u003c/h4\u003e\n\nAlias of \u003ca href=\"#map\"\u003emap()\u003c/a\u003e.\n\n\u003ch4\u003e\u003ca name=\"detect\"\u003e\u003c/a\u003edetect(callable $fn, bool $useValue): mixed|null\u003c/h4\u003e\n\nAlias of \u003ca href=\"#find\"\u003efind()\u003c/a\u003e.\n\n\u003ch4\u003e\u003ca name=\"drop\"\u003e\u003c/a\u003edrop(int $n): array|mixed\u003c/h4\u003e\n\nAlias of \u003ca href=\"#last\"\u003elast()\u003c/a\u003e.\n\n\u003ch4\u003e\u003ca name=\"foldl\"\u003e\u003c/a\u003efoldl(callable $fn, mixed $memo): mixed\u003c/h4\u003e\n\nAlias of \u003ca href=\"#reduce\"\u003ereduce()\u003c/a\u003e.\n\n\u003ch4\u003e\u003ca name=\"foldr\"\u003e\u003c/a\u003efoldr(callable $fn, mixed $memo): mixed\u003c/h4\u003e\n\nAlias of \u003ca href=\"#reduceRight\"\u003ereduceRight()\u003c/a\u003e.\n\n\u003ch4\u003e\u003ca name=\"head\"\u003e\u003c/a\u003ehead(int $n): array|mixed\u003c/h4\u003e\n\nAlias of \u003ca href=\"#first\"\u003efirst()\u003c/a\u003e.\n\n\u003ch4\u003e\u003ca name=\"includes\"\u003e\u003c/a\u003eincludes(): void\u003c/h4\u003e\n\nAlias of \u003ca href=\"#contains\"\u003econtains()\u003c/a\u003e.\n\n\u003ch4\u003e\u003ca name=\"inject\"\u003e\u003c/a\u003einject(callable $fn, mixed $memo): mixed\u003c/h4\u003e\n\nAlias of \u003ca href=\"#reduce\"\u003ereduce()\u003c/a\u003e.\n\n\u003ch4\u003e\u003ca name=\"select\"\u003e\u003c/a\u003eselect(callable|string|null $fn): self\u003c/h4\u003e\n\nAlias of \u003ca href=\"#filter\"\u003efilter()\u003c/a\u003e.\n\n\u003ch4\u003e\u003ca name=\"size\"\u003e\u003c/a\u003esize(): int\u003c/h4\u003e\n\nAlias of \u003ca href=\"#count\"\u003ecount()\u003c/a\u003e.\n\n\u003ch4\u003e\u003ca name=\"tail\"\u003e\u003c/a\u003etail(int $n): array|mixed\u003c/h4\u003e\n\nAlias of \u003ca href=\"#last\"\u003elast()\u003c/a\u003e.\n\n\u003ch4\u003e\u003ca name=\"take\"\u003e\u003c/a\u003etake(int $n): array|mixed\u003c/h4\u003e\n\nAlias of \u003ca href=\"#first\"\u003efirst()\u003c/a\u003e.\n\n\u003ch4\u003e\u003ca name=\"uniq\"\u003e\u003c/a\u003euniq(callable|string $fn): self\u003c/h4\u003e\n\nAlias of \u003ca href=\"#unique\"\u003eunique()\u003c/a\u003e.\n\n\u003ch4\u003e\u003ca name=\"without\"\u003e\u003c/a\u003ewithout(array|mixed $data): self\u003c/h4\u003e\n\nAlias of \u003ca href=\"#difference\"\u003edifference()\u003c/a\u003e.\n\n---\n### HigherOrderMessage\n\nA syntatic sugar to use elegant shorthand oneliner for complex logic often wrapped in closures.\nSee example below:\n\n```php\n// Higher Order Messaging\nclass HOM\n{\n    protected $n;\n    public $square;\n\n    public function __construct($n)\n    {\n        $this-\u003en      = $n;\n        $this-\u003esquare = $n * $n;\n    }\n\n    public function even()\n    {\n        return $this-\u003en % 2 === 0;\n    }\n}\n\n$u = [new HOM(1), new HOM(2), new HOM(3), new HOM(4)];\n\n// Filter `even()` items\n$evens = $u-\u003efilter-\u003eeven(); // 'even()' method of each items!\n\n// Map each evens to their squares\n$squares = $evens-\u003emap-\u003esquare; // 'square' prop of each items!\n// Gives an Underscore instance\n\n// Get the data\n$squares-\u003eget();\n// [1 =\u003e 4, 3 =\u003e 16]\n```\n\nWithout higher order messaging that would look like:\n\n```php\n$evens = $u-\u003efilter(function ($it) {\n    return $it-\u003eeven();\n});\n\n$squares = $evens-\u003emap(function ($it) {\n    return $it-\u003esquare;\n});\n```\n\n---\n### \\ArrayAccess\n\nUnderscore instances can be treated as array:\n\n```php\n$u = underscore([1, 2, 'a' =\u003e 3]);\n\nisset($u['a']); // true\nisset($u['b']); // false\n\necho $u[1];     // 2\n\n$u['b'] = 'B';\nisset($u['b']); // true\n\nunset($u[1]);\n```\n\n---\n### Arrayizes\n\nYou can use this trait to arrayize all complex data.\n\n```php\nuse Ahc\\Underscore\\Arrayizes;\n\nclass Any\n{\n    use Arrayizes;\n\n    public function name()\n    {\n        $this-\u003easArray($data);\n    }\n}\n```\n\n---\n#### License\n\n\u003e [MIT](./LICENSE) | \u0026copy; 2017-2018 | Jitendra Adhikari\n","funding_links":["https://github.com/sponsors/adhocore","https://paypal.me/ji10","https://www.paypal.me/ji10/15usd","https://www.paypal.me/ji10/25usd","https://www.paypal.me/ji10/50usd"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadhocore%2Fphp-underscore","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadhocore%2Fphp-underscore","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadhocore%2Fphp-underscore/lists"}