From 1ab8ca471959bc72c025a33cd385615d9c220da3 Mon Sep 17 00:00:00 2001 From: jjgrainger Date: Sun, 1 Feb 2026 16:40:31 +0000 Subject: [PATCH 1/8] update phpstan level to 5 and fixes --- phpstan.neon.dist | 2 +- src/Collection.php | 245 +++++++++++++++++++++++++++------------------ 2 files changed, 148 insertions(+), 99 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 1636bf2..18c973a 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,5 +1,5 @@ parameters: - level: 0 + level: 5 paths: - src ignoreErrors: diff --git a/src/Collection.php b/src/Collection.php index ea5536e..66b65ef 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -11,34 +11,52 @@ class Collection implements Countable, IteratorAggregate, JsonSerializable { - - protected $items; + /** + * Collection items. + * + * @var array + */ + protected array $items; /** - * Create a collection from passed items + * Create a collection with items passed. + * * @param array $items */ - public function __construct($items = []) + public function __construct(array $items = []) { $this->items = $items; } /** - * Return udnerlying array in collection + * Create a collection statically. + * + * @param array $items + * @return static + */ + public static function collect(array $items): static + { + return new static($items); + } + + /** + * Return items in the collection. + * * @return array */ - public function all() + public function all(): array { return $this->items; } /** - * Get an item in the collection by its key - * @param mixed $key - * @param mixed $default + * Get an item by key. + * + * @param string|int $key + * @param mixed $default * @return mixed */ - public function get($key, $default = null) + public function get(string|int $key, mixed $default = null): mixed { if ($this->has($key)) { return $this->items[$key]; @@ -48,45 +66,45 @@ public function get($key, $default = null) } /** - * Check if key exists in the collection - * @param mixed $key + * Check if key exists in the collection. + * + * @param string|int $key * @return boolean */ - public function has($key) + public function has(string|int $key): bool { - if (isset($this->items[$key])) { - return true; - } - - return false; + return isset($this->items[$key]); } /** - * Set a key and value to the collection - * @param mixed $key - * @param mixed $value + * Put value to collection with key. + * + * @param string|int $key + * @param mixed $value */ - public function put($key, $value) + public function put(string|int $key, mixed $value): void { $this->items[$key] = $value; } /** - * Add item to the end of the collection - * @param mixed $value + * Add item to the end of the collection. + * + * @param mixed $value */ - public function push($value) + public function push(mixed $value): void { $this->items[] = $value; } /** - * Remove and return an item via its key - * @param mixed $key - * @param mixed $default + * Remove and return an item via its key. + * + * @param string|int $key + * @param mixed $default * @return mixed */ - public function pull($key, $default = null) + public function pull(string|int $key, mixed $default = null): mixed { $value = $this->get($key, $default); @@ -96,63 +114,71 @@ public function pull($key, $default = null) } /** - * Return the first item in the collection + * Return the first item in the collection. + * * @return mixed */ - public function first() + public function first(): mixed { return count($this->items) ? reset($this->items) : null; } /** - * Return the last item in the collection + * Return the last item in the collection. + * * @return mixed */ - public function last() + public function last(): mixed { return count($this->items) ? end($this->items) : null; } /** - * Return and remove the last item in the array + * Return and remove the last item in the array. + * * @return mixed */ - public function pop() + public function pop(): mixed { return array_pop($this->items); } /** - * Return and remove the first item in the array + * Return and remove the first item in the array. + * * @return mixed */ - public function shift() + public function shift(): mixed { return array_shift($this->items); } /** - * Remove item from the collection via its key - * @param mixed $key + * Remove item from the collection via its key. + * + * @param string|int $key */ - public function remove($key) + public function remove(string|int $key): void { unset($this->items[$key]); } /** - * Return the collection keys as a new collection - * @return Collection + * Return the collection keys as a new collection. + * + * @return static */ - public function keys() + public function keys(): static { return new static(array_keys($this->items)); } /** - * Reset the collections keys + * Reset the collections keys. + * + * @return static */ - public function values() + public function values(): static { $this->items = array_values($this->items); @@ -160,10 +186,11 @@ public function values() } /** - * Transform the current collection - * @param Closure $iterator + * Transform the current collection. + * + * @param callable $iterator */ - public function transform(Closure $iterator) + public function transform(callable $iterator): static { $this->items = array_map($iterator, $this->items); @@ -171,28 +198,31 @@ public function transform(Closure $iterator) } /** - * Returns a collection without duplicate values - * @return Collection + * Returns a collection without duplicate values. + * + * @return static */ - public function unique() + public function unique(): static { return new static(array_unique($this->items, SORT_REGULAR)); } /** - * Return a new collection with the items reverese - * @return Collection + * Return a new collection with the items reverse. + * + * @return static */ - public function reverse() + public function reverse(): static { return new static(array_reverse($this->items)); } /** - * Return a new collection with the items shuffled - * @return Collection + * Return a new collection with the items shuffled. + * + * @return static */ - public function shuffle() + public function shuffle(): static { $items = $this->items; @@ -202,10 +232,12 @@ public function shuffle() } /** - * Get one or more items randomly from the collection - * @param integer $amount + * Get one or more items randomly from the collection. + * + * @param int $amount + * @return mixed */ - public function random($amount = 1) + public function random(int $amount = 1): mixed { if ($this->isEmpty()) { return null; @@ -221,50 +253,55 @@ public function random($amount = 1) } /** - * Flip items in the collection - * @return Collection + * Flip items in the collection. + * + * @return static */ - public function flip() + public function flip(): static { return new static(array_flip($this->items)); } /** - * Map over each of the items in the collection - * @param Closure $iterator - * @return Collection + * Map over each of the items in the collection. + * + * @param callable $iterator + * @return static */ - public function map(Closure $iterator) + public function map(callable $iterator): static { return new static(array_map($iterator, $this->items)); } /** - * Filter items within the collection - * @param Closure $filter - * @return Collection + * Filter items within the collection. + * + * @param callable $filter + * @return static */ - public function filter(Closure $filter) + public function filter(?callable $filter): static { return new static(array_filter($this->items, $filter)); } /** - * Reduce the collection to a single value - * @param Closure $callback - * @param mixed $initial - * @return Collection + * Reduce the collection to a single value. + * + * @param callable $callback + * @param mixed $initial + * @return mixed */ - public function reduce(Closure $callback, $initial = null) + public function reduce(callable $callback, $initial = null): mixed { return array_reduce($this->items, $callback, $initial); } /** - * Sum the items in the collection - * @param string $key + * Sum the items in the collection. + * + * @param string|int|null $key */ - public function sum($key = null) + public function sum(string|int|null $key = null): int { if (is_null($key)) { return array_sum($this->items); @@ -276,16 +313,19 @@ public function sum($key = null) } /** - * Concatenate items into a string - * @param string $glue + * Concatenate items into a string. + * + * @param string $glue + * @return string */ - public function implode($glue = '') + public function implode(string $glue = ''): string { return implode($glue, $this->items); } /** - * Return total items in collection + * Return total items in collection. + * * @return int */ public function count(): int @@ -294,44 +334,51 @@ public function count(): int } /** - * Check if the collection is empty + * Check if the collection is empty. + * * @return boolean */ - public function isEmpty() + public function isEmpty(): bool { return empty($this->items); } /** - * Check if the collection is not empty + * Check if the collection is not empty. + * * @return boolean */ - public function isNotEmpty() + public function isNotEmpty(): bool { - return !empty($this->items); + return ! $this->isEmpty(); } /** - * Return the collection as an array - * @return Array + * Return the collection as an array. + * + * @return array */ - public function toArray() + public function toArray(): array { return $this->items; } /** - * Return the collection as JSON - * @param integer $options - * @return string + * Return the collection as JSON. + * + * @param int $flags + * @param int $depth + * @return string|false */ - public function toJson($options = 0) + public function toJson(int $flags = 0, int $depth = 512): string|false { - return json_encode($this->items, $options); + return json_encode($this->items, $flags, $depth); } /** - * Iterate over items in collection + * Iterate over items in collection. + * + * @return Traversable */ public function getIterator(): Traversable { @@ -339,7 +386,9 @@ public function getIterator(): Traversable } /** - * JSON Serialize items in the collection + * JSON Serialize items in the collection. + * + * @return mixed */ public function jsonSerialize(): mixed { From 5f2f5bf0a27089590e18a9bfa3a0c3358bc0c471 Mon Sep 17 00:00:00 2001 From: jjgrainger Date: Sun, 1 Feb 2026 16:41:31 +0000 Subject: [PATCH 2/8] add coverage reporting --- .github/workflows/tests.yml | 7 ++++++- .gitignore | 1 + composer.json | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 65866da..29209c2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -59,4 +59,9 @@ jobs: run: composer install --prefer-dist --no-progress - name: PHPUnit - run: composer phpunit + run: composer phpunit:coverage + + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v5 + with: + token: ${{ secrets.CODECOV_TOKEN }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index f8892ba..f562caf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .DS_Store /vendor .phpunit.result.cache +coverage.xml \ No newline at end of file diff --git a/composer.json b/composer.json index fa7999a..f151c84 100644 --- a/composer.json +++ b/composer.json @@ -26,6 +26,7 @@ "scripts": { "phpcs": "./vendor/bin/phpcs --standard=psr2 src", "phpunit": "./vendor/bin/phpunit", + "phpunit:coverage": "./vendor/bin/phpunit --coverage-clover=coverage.xml", "phpstan": "phpstan analyse src" } } From faa3b0669a03651c461c6bac5d21d71a70ad6c31 Mon Sep 17 00:00:00 2001 From: jjgrainger Date: Sun, 1 Feb 2026 16:43:57 +0000 Subject: [PATCH 3/8] add .editorconfig and remove whitespace --- .editorconfig | 8 ++++++ src/Collection.php | 62 +++++++++++++++++++++++----------------------- 2 files changed, 39 insertions(+), 31 deletions(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..0763a70 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,8 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = space diff --git a/src/Collection.php b/src/Collection.php index 66b65ef..ebbe343 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -20,7 +20,7 @@ class Collection implements Countable, IteratorAggregate, JsonSerializable /** * Create a collection with items passed. - * + * * @param array $items */ public function __construct(array $items = []) @@ -41,7 +41,7 @@ public static function collect(array $items): static /** * Return items in the collection. - * + * * @return array */ public function all(): array @@ -51,7 +51,7 @@ public function all(): array /** * Get an item by key. - * + * * @param string|int $key * @param mixed $default * @return mixed @@ -67,7 +67,7 @@ public function get(string|int $key, mixed $default = null): mixed /** * Check if key exists in the collection. - * + * * @param string|int $key * @return boolean */ @@ -89,7 +89,7 @@ public function put(string|int $key, mixed $value): void /** * Add item to the end of the collection. - * + * * @param mixed $value */ public function push(mixed $value): void @@ -99,7 +99,7 @@ public function push(mixed $value): void /** * Remove and return an item via its key. - * + * * @param string|int $key * @param mixed $default * @return mixed @@ -115,7 +115,7 @@ public function pull(string|int $key, mixed $default = null): mixed /** * Return the first item in the collection. - * + * * @return mixed */ public function first(): mixed @@ -125,7 +125,7 @@ public function first(): mixed /** * Return the last item in the collection. - * + * * @return mixed */ public function last(): mixed @@ -135,7 +135,7 @@ public function last(): mixed /** * Return and remove the last item in the array. - * + * * @return mixed */ public function pop(): mixed @@ -145,7 +145,7 @@ public function pop(): mixed /** * Return and remove the first item in the array. - * + * * @return mixed */ public function shift(): mixed @@ -155,7 +155,7 @@ public function shift(): mixed /** * Remove item from the collection via its key. - * + * * @param string|int $key */ public function remove(string|int $key): void @@ -165,7 +165,7 @@ public function remove(string|int $key): void /** * Return the collection keys as a new collection. - * + * * @return static */ public function keys(): static @@ -175,7 +175,7 @@ public function keys(): static /** * Reset the collections keys. - * + * * @return static */ public function values(): static @@ -187,7 +187,7 @@ public function values(): static /** * Transform the current collection. - * + * * @param callable $iterator */ public function transform(callable $iterator): static @@ -199,7 +199,7 @@ public function transform(callable $iterator): static /** * Returns a collection without duplicate values. - * + * * @return static */ public function unique(): static @@ -209,7 +209,7 @@ public function unique(): static /** * Return a new collection with the items reverse. - * + * * @return static */ public function reverse(): static @@ -219,7 +219,7 @@ public function reverse(): static /** * Return a new collection with the items shuffled. - * + * * @return static */ public function shuffle(): static @@ -233,7 +233,7 @@ public function shuffle(): static /** * Get one or more items randomly from the collection. - * + * * @param int $amount * @return mixed */ @@ -254,7 +254,7 @@ public function random(int $amount = 1): mixed /** * Flip items in the collection. - * + * * @return static */ public function flip(): static @@ -264,7 +264,7 @@ public function flip(): static /** * Map over each of the items in the collection. - * + * * @param callable $iterator * @return static */ @@ -275,7 +275,7 @@ public function map(callable $iterator): static /** * Filter items within the collection. - * + * * @param callable $filter * @return static */ @@ -286,7 +286,7 @@ public function filter(?callable $filter): static /** * Reduce the collection to a single value. - * + * * @param callable $callback * @param mixed $initial * @return mixed @@ -298,7 +298,7 @@ public function reduce(callable $callback, $initial = null): mixed /** * Sum the items in the collection. - * + * * @param string|int|null $key */ public function sum(string|int|null $key = null): int @@ -314,7 +314,7 @@ public function sum(string|int|null $key = null): int /** * Concatenate items into a string. - * + * * @param string $glue * @return string */ @@ -325,7 +325,7 @@ public function implode(string $glue = ''): string /** * Return total items in collection. - * + * * @return int */ public function count(): int @@ -335,7 +335,7 @@ public function count(): int /** * Check if the collection is empty. - * + * * @return boolean */ public function isEmpty(): bool @@ -345,7 +345,7 @@ public function isEmpty(): bool /** * Check if the collection is not empty. - * + * * @return boolean */ public function isNotEmpty(): bool @@ -355,7 +355,7 @@ public function isNotEmpty(): bool /** * Return the collection as an array. - * + * * @return array */ public function toArray(): array @@ -365,7 +365,7 @@ public function toArray(): array /** * Return the collection as JSON. - * + * * @param int $flags * @param int $depth * @return string|false @@ -377,7 +377,7 @@ public function toJson(int $flags = 0, int $depth = 512): string|false /** * Iterate over items in collection. - * + * * @return Traversable */ public function getIterator(): Traversable @@ -387,7 +387,7 @@ public function getIterator(): Traversable /** * JSON Serialize items in the collection. - * + * * @return mixed */ public function jsonSerialize(): mixed From f5a53be3e16b59a0f7cf06f23d144cf057d54390 Mon Sep 17 00:00:00 2001 From: jjgrainger Date: Sun, 1 Feb 2026 16:48:32 +0000 Subject: [PATCH 4/8] update phpunit.xml for coverage reporting --- phpunit.xml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/phpunit.xml b/phpunit.xml index 90b6d3e..5122c52 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -4,8 +4,14 @@ verbose="true" stopOnFailure="false"> - + tests + + + + src + + From 1533a984ed22bc92cd5fdb1e4ef392d9a2eb9385 Mon Sep 17 00:00:00 2001 From: jjgrainger Date: Sun, 1 Feb 2026 16:55:08 +0000 Subject: [PATCH 5/8] add configuration to phpunit:coverage script --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index f151c84..77111d3 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ "scripts": { "phpcs": "./vendor/bin/phpcs --standard=psr2 src", "phpunit": "./vendor/bin/phpunit", - "phpunit:coverage": "./vendor/bin/phpunit --coverage-clover=coverage.xml", + "phpunit:coverage": "./vendor/bin/phpunit --configuration phpunit.xml --coverage-clover=coverage.xml", "phpstan": "phpstan analyse src" } } From 4a146d69bce492f90c800d916fa053499bd7ea01 Mon Sep 17 00:00:00 2001 From: jjgrainger Date: Sun, 1 Feb 2026 17:01:50 +0000 Subject: [PATCH 6/8] fix directory --- phpunit.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpunit.xml b/phpunit.xml index 5122c52..36ab660 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -11,7 +11,7 @@ - src + ./src From 5174adddc9490b9b29a71b766704c545057979cd Mon Sep 17 00:00:00 2001 From: jjgrainger Date: Sun, 1 Feb 2026 17:06:50 +0000 Subject: [PATCH 7/8] update phpunit.xml --- composer.json | 1 + phpunit.xml | 13 +++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/composer.json b/composer.json index 77111d3..c0f5495 100644 --- a/composer.json +++ b/composer.json @@ -25,6 +25,7 @@ }, "scripts": { "phpcs": "./vendor/bin/phpcs --standard=psr2 src", + "phpcbf": "./vendor/bin/phpcbf --standard=psr2 src", "phpunit": "./vendor/bin/phpunit", "phpunit:coverage": "./vendor/bin/phpunit --configuration phpunit.xml --coverage-clover=coverage.xml", "phpstan": "phpstan analyse src" diff --git a/phpunit.xml b/phpunit.xml index 36ab660..2252722 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,17 +1,18 @@ - + tests - + ./src - + From 6ba277181fbd3ac92e36e90033dd7d973c44943f Mon Sep 17 00:00:00 2001 From: jjgrainger Date: Sun, 1 Feb 2026 17:09:58 +0000 Subject: [PATCH 8/8] add coverage badge to README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 870809a..897b428 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ > A collection class for working with arrays -[![tests](https://github.com/jjgrainger/Collection/actions/workflows/tests.yml/badge.svg)](https://github.com/jjgrainger/Collection/actions/workflows/tests.yml) [![Latest Stable Version](https://badgen.net/github/release/jjgrainger/Collection/stable)](https://packagist.org/packages/jjgrainger/collection) [![Total Downloads](https://badgen.net/packagist/dt/jjgrainger/Collection)](https://packagist.org/packages/jjgrainger/collection) [![License](https://badgen.net/github/license/jjgrainger/Collection)](https://packagist.org/packages/jjgrainger/collection) +[![tests](https://github.com/jjgrainger/Collection/actions/workflows/tests.yml/badge.svg)](https://github.com/jjgrainger/Collection/actions/workflows/tests.yml) [![codecov](https://codecov.io/gh/jjgrainger/Collection/graph/badge.svg?token=XMLzVOcLHB)](https://codecov.io/gh/jjgrainger/Collection) [![Latest Stable Version](https://badgen.net/github/release/jjgrainger/Collection/stable)](https://packagist.org/packages/jjgrainger/collection) [![Total Downloads](https://badgen.net/packagist/dt/jjgrainger/Collection)](https://packagist.org/packages/jjgrainger/collection) [![License](https://badgen.net/github/license/jjgrainger/Collection)](https://packagist.org/packages/jjgrainger/collection) ## Principles