diff --git a/docs/pages/api.rst b/docs/pages/api.rst index 5d24720af..1bc98f799 100644 --- a/docs/pages/api.rst +++ b/docs/pages/api.rst @@ -153,7 +153,7 @@ Create a collection by yielding from a callback with an initial value. on the next callback call. Therefore, the returned list should contain values of the same type as the parameters for the callback function. -Signature: ``Collection::unfold(callable $callback, ...$parameters): Collection;`` +Signature: ``Collection::unfold(callable $callback, $parameters): Collection;`` .. literalinclude:: code/operations/unfold.php :language: php diff --git a/docs/pages/code/operations/unfold.php b/docs/pages/code/operations/unfold.php index 6a26fb6d5..6c938fe30 100644 --- a/docs/pages/code/operations/unfold.php +++ b/docs/pages/code/operations/unfold.php @@ -11,7 +11,7 @@ include __DIR__ . '/../../../../vendor/autoload.php'; // Example 1 -> A list of Naturals from 1 to Infinity (use `limit` to keep only a set of them) -Collection::unfold(static fn (int $n): array => [$n + 1], 1) +Collection::unfold(static fn (int $n): array => [$n + 1], [1]) ->unwrap() ->all(); // [1, 2, 3, 4, ...] @@ -22,8 +22,8 @@ ->all(); // [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] // Example 3 -> infinite range, similar to the `range` operation -$even = Collection::unfold(static fn ($carry): array => [$carry + 2], -2)->unwrap(); -$odd = Collection::unfold(static fn ($carry): array => [$carry + 2], -1)->unwrap(); +$even = Collection::unfold(static fn ($carry): array => [$carry + 2], [-2])->unwrap(); +$odd = Collection::unfold(static fn ($carry): array => [$carry + 2], [-1])->unwrap(); // Is the same as $even = Collection::range(0, INF, 2); diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 4d6754c7c..75e2e5f57 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -460,6 +460,11 @@ parameters: count: 1 path: src/Operation/Transpose.php + - + message: "#^Template type U of method loophp\\\\collection\\\\Operation\\\\Unfold\\:\\:__invoke\\(\\) is not referenced in a parameter\\.$#" + count: 1 + path: src/Operation/Unfold.php + - message: "#^While loop condition is always true\\.$#" count: 1 diff --git a/src/Collection.php b/src/Collection.php index 7cd8108f0..3021a2328 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -890,9 +890,9 @@ public function truthy(): bool return (new Truthy())()($this)->current(); } - public static function unfold(callable $callback, ...$parameters): CollectionInterface + public static function unfold(callable $callback, array $parameters = []): CollectionInterface { - return new self((new Unfold())()(...$parameters)($callback)); + return new self((new Unfold())()($parameters)($callback)); } public function unlines(): string diff --git a/src/Contract/Collection.php b/src/Contract/Collection.php index dee63057e..d0500e0f5 100644 --- a/src/Contract/Collection.php +++ b/src/Contract/Collection.php @@ -238,6 +238,7 @@ * @template-extends TakeWhileable * @template-extends Transposeable * @template-extends Truthyable + * @template-extends Unfoldable * @template-extends Unlinesable * @template-extends Unpackable * @template-extends Unpairable diff --git a/src/Contract/Operation/Unfoldable.php b/src/Contract/Operation/Unfoldable.php index 22f4f3805..42fd4cf2e 100644 --- a/src/Contract/Operation/Unfoldable.php +++ b/src/Contract/Operation/Unfoldable.php @@ -6,6 +6,10 @@ use loophp\collection\Contract\Collection; +/** + * @template TKey + * @template T + */ interface Unfoldable { /** @@ -13,12 +17,12 @@ interface Unfoldable * * @see https://loophp-collection.readthedocs.io/en/stable/pages/api.html#unfold * - * @template T + * @template U * - * @param callable(T ...): list $callback - * @param T ...$parameters + * @param callable((T|U) ...): list $callback + * @param array $parameters * * @return Collection> */ - public static function unfold(callable $callback, ...$parameters): Collection; + public static function unfold(callable $callback, array $parameters = []): Collection; } diff --git a/src/Operation/Unfold.php b/src/Operation/Unfold.php index cca38afe8..9e77c471d 100644 --- a/src/Operation/Unfold.php +++ b/src/Operation/Unfold.php @@ -18,19 +18,21 @@ final class Unfold extends AbstractOperation { /** - * @return Closure(T...): Closure(callable(T...): list): Closure(): Generator> + * @template U + * + * @return Closure(array): Closure(callable((T|U)...): list): Closure(): Generator> */ public function __invoke(): Closure { return /** - * @param T ...$parameters + * @param array $parameters * - * @return Closure(callable(T...): list): Closure(): Generator> + * @return Closure(callable((T|U)...): list): Closure(): Generator> */ - static fn (...$parameters): Closure => + static fn ($parameters): Closure => /** - * @param callable(T...): list $callback + * @param callable((T|U)...): list $callback * * @return Closure(): Generator> */ diff --git a/tests/static-analysis/unfold.php b/tests/static-analysis/unfold.php index 07e6fbb8d..14381c6a5 100644 --- a/tests/static-analysis/unfold.php +++ b/tests/static-analysis/unfold.php @@ -24,17 +24,22 @@ function unfold_checkListOfLists(CollectionInterface $collection): void $fib = static fn (int $a = 0, int $b = 1): array => [$b, $a + $b]; unfold_checkList(Collection::unfold($plusTwo)->unwrap()); -unfold_checkList(Collection::unfold($plusTwo, -2)->unwrap()); +unfold_checkList(Collection::unfold($plusTwo, [-2])->unwrap()); // VALID use cases -> PHPStan thinks the collection is of type Collection>, but Psalm works /** @phpstan-ignore-next-line */ unfold_checkListOfLists(Collection::unfold($plusTwo)); -/** @phpstan-ignore-next-line */ +/** @psalm-suppress InvalidArgument @phpstan-ignore-next-line */ unfold_checkListOfLists(Collection::unfold($plusTwo, -2)); /** @phpstan-ignore-next-line */ unfold_checkListOfLists(Collection::unfold($fib)); -/** @phpstan-ignore-next-line */ +/** + * @psalm-suppress InvalidArgument + * @psalm-suppress TooManyArguments + * + * @phpstan-ignore-next-line + */ unfold_checkListOfLists(Collection::unfold($fib, 0, 1)); // VALID use case -> `Pluck` can return various things so analysers cannot know the type is correct diff --git a/tests/unit/CollectionConstructorsTest.php b/tests/unit/CollectionConstructorsTest.php index 0c7f34747..ee0e2a507 100644 --- a/tests/unit/CollectionConstructorsTest.php +++ b/tests/unit/CollectionConstructorsTest.php @@ -307,7 +307,7 @@ public function testUnfoldConstructor(): void { $this::assertIdenticalIterable( [[0], [2], [4], [6], [8]], - Collection::unfold(static fn (int $n): array => [$n + 2], -2)->limit(5) + Collection::unfold(static fn (int $n): array => [$n + 2], [-2])->limit(5) ); } }