{"id":16675883,"url":"https://github.com/harmenjanssen/lazycollection","last_synced_at":"2026-05-19T11:43:54.052Z","repository":{"id":62514748,"uuid":"104670602","full_name":"harmenjanssen/lazycollection","owner":"harmenjanssen","description":"Lazy collections in PHP using generators.","archived":false,"fork":false,"pushed_at":"2017-09-25T04:51:43.000Z","size":21,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-01-01T09:09:04.772Z","etag":null,"topics":["generators","lazy","php"],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/harmenjanssen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-09-24T19:30:44.000Z","updated_at":"2022-11-17T06:38:04.000Z","dependencies_parsed_at":"2022-11-02T13:15:55.675Z","dependency_job_id":null,"html_url":"https://github.com/harmenjanssen/lazycollection","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/harmenjanssen/lazycollection","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/harmenjanssen%2Flazycollection","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/harmenjanssen%2Flazycollection/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/harmenjanssen%2Flazycollection/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/harmenjanssen%2Flazycollection/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/harmenjanssen","download_url":"https://codeload.github.com/harmenjanssen/lazycollection/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/harmenjanssen%2Flazycollection/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33214695,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-19T07:54:09.561Z","status":"ssl_error","status_checked_at":"2026-05-19T07:54:08.508Z","response_time":58,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["generators","lazy","php"],"created_at":"2024-10-12T13:08:17.293Z","updated_at":"2026-05-19T11:43:54.034Z","avatar_url":"https://github.com/harmenjanssen.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# LazyCollection\n\n## What's this?\n\nA `LazyCollection` class that takes care of creating a [generator](http://php.net/manual/en/language.generators.php) for your collection.  \nGenerators don't work with the standard `map`, `filter` and `reduce` functions in PHP.  \nThis is a shame of course because you lose a lot of handy abstractions. This package implements those methods lazily.\n\nConsider the following example with traditional arrays:\n\n```php\n$square = function($x) {\n  return $x * $x;\n};\n$isEven = function($x) {\n  return $x % 2 === 0;\n};\n\n$highestEvenSquare = array_filter(\n    array_map(\n        $square,\n        range(30, 0)\n    ),\n    $isEven\n)[0];\n```\n\nThis requires the entire range to be created, mapped to squares, and filtered before we can grab the first item.\n\nWith `LazyCollection`, this could be implemented like this:\n\n```php\n$lazyCollection = new LazyCollection\\Examples\\LazyArray(range(29, 0));\n$lazyCollection-\u003emap($square)\n    -\u003efilter($isEven)\n    -\u003efirst();\n```\n\nOf course, the initial range will be created in memory, but only the first two items would need to be squared and filtered.\nSince the second item, 28, is a match to our filter function (28 * 28 results in the even number 784), `first()` will just stop there.\nThe rest of the squares won't be computed.  \n\nIt's easy to imagine a collection where every next item is computed on the spot, in which case the original array doesn't even have to be \ncreated in memory (for instance: search a large database or file until a fixed number of matches is found).\n\n## Installation\n\nInstall using Composer: \n\n```\ncomposer require harmenjanssen/lazycollection\n```\n\n## Usage\n\n`all()`\n- This method returns the actual `Generator`:\n\n```php\n$numbers = LazyCollection\\Examples\\Numbers::from(1);\nforeach ($numbers-\u003etake(100)-\u003eall() as $n) {\n    echo $n . \"\\n\";\n}\n// will echo numbers 1 through 100\n```\n\n`first()`\n- Take the first item of the collection.\n\n`take(int $amount): Subset`\n- Limits the collection to the given amount. Returns a new `LazyCollection` of type `Subset`. \n  See example under `all()`.\n\n`slice(int $start, int $length): Subset`\n- Take a subset of `$length` items of the collection starting at `$start`.\n\n```php\n$numbers = LazyCollection\\Examples\\Numbers::from(1);\n$fifty = $numbers-\u003eslice(50, 10);\n\niterator_to_array($fifty); // [50, 51, ... 60]\n```\n\n`map(callable $transformer): Mapped`\n- Add a mapping function to the collection. Returns a new `LazyCollection` of type `Mapped`.\n    \n```php\n$numbers = LazyCollection\\Examples\\Numbers::from(1);\n$squares = $numbers-\u003emap(function($x) {\n    return $x * $x;\n});\n\niterator_to_array($squares-\u003etake(10)); // [1, 4, 9, 16, 25... 100]\n```\n\n`filter(callable $predicate): Filtered`\n- Add a filter function to the collection. Returns a new `LazyCollection` of type `Filtered`.\n\n```php\n$numbers = LazyCollection\\Examples\\Numbers::from(1);\n$evenStevens = $numbers-\u003efilter(function($x) {\n    return $x % 2 === 0;\n});\n\niterator_to_array($evenStevens-\u003etake(10)); // [2, 4, 6, 8, 10... 20]\n```\n\n`reduce(callable $reducer, $seed)`\n- Reduce the collection to a single value.\n\n```php\n$numbers = LazyCollection\\Examples\\Numbers::from(1)-\u003etake(10);\n$sum = $numbers-\u003ereduce(function($a, $b) {\n    return $a + $b;\n}, 0); // 55\n```\n\n## Implement your own lazy collections\n\nCreate a subclass of `LazyCollection`, implementing the 4 required methods:\n\n`start()`\n- Returns the initial iteration. Note that this is not the same as an iteration's value, \n  nor does it have to be numeric. You determine how you iterate your collection and what \n  data you need to progress through it.\n  See the Fibonacci example for a collection that uses an array to track progress through \n  the collection\n\n`next($iteration)`\n- Returns the next iteration based on the previous iteration.\n  Note that the return type and the type of its parameter are the same as those of `start()`, most likely.\n\n`done(): bool`\n- Wether iteration is done. \n\n`value($iteration)`\n- Return a value based on the given iteration.\n\n\n## Infinite collections\n\nInfinite collection are elegant solutions to computational patterns. \nBoth the [Numbers](https://github.com/harmenjanssen/lazycollection/blob/master/examples/Numbers.php) sequence and the [Fibonacci](https://github.com/harmenjanssen/lazycollection/blob/master/examples/Fibonacci.php) sequence are examples of infinite collections.  \nYou can project a range of values, but there's no natural end.\n\nEven though iterating over these collections is no problem, you have to make sure you bring iteration to a halt yourself, or you'll run out of memory.\n`take()` is a handy method to use in this case.\n\n```php\n$fibonacci = new LazyCollection\\Examples\\Fibonacci;\niterator_to_array($fibonacci-\u003etake(10)-\u003eall()); // [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]\n```\n\nAlso consider this pitfall: when filtering an infinite collection by a predicate _that matches nothing_, the filter will \nnot return an empty collection, as it would with regular arrays. It will run out of memory since it never ends.\n\n```php\n// This will never resolve:\n\n$fibonacci = new LazyCollection\\Examples\\Fibonacci;\n$fibonacci-\u003efilter('is_string')-\u003etake(10);\n```\n\nNote also that you cannot use `iterator_to_array` to flatten the iterator into an array. Again, this would never end.\n\n## Todos\n\n- Implement `until()`\n- Implement `find()`\n\n## Inspiration\n\nI picked up the concept of functional iterators from the wonderful book [Javascript Allongé](https://leanpub.com/javascriptallongesix/), by [Reginald Braithwaite](https://github.com/raganwald).\n\nLots of interesting languages support the concept of lazy (possibly infinite) sequences, like Haskell and Clojure.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fharmenjanssen%2Flazycollection","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fharmenjanssen%2Flazycollection","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fharmenjanssen%2Flazycollection/lists"}