diff --git a/docs/pages/api.rst b/docs/pages/api.rst index 1d64d9878..c0f3a40ba 100644 --- a/docs/pages/api.rst +++ b/docs/pages/api.rst @@ -1279,14 +1279,14 @@ map Apply a single callback to every item of a collection and use the return value. .. warning:: An earlier version of this operation allowed usage with multiple callbacks. This behaviour - is deprecated and will be removed in a future major version; ``mapN`` should be used instead, or, + was removed in version ``5.0``; ``mapN`` should be used instead, or, alternatively, multiple successive ``map`` calls can achieve the same result. .. warning:: Keys are preserved, use the ``Collection::normalize`` operation if you want to re-index the keys. Interface: `Mapable`_ -Signature: ``Collection::map(callable ...$callbacks);`` +Signature: ``Collection::map(callable $callbacks);`` .. code-block:: php diff --git a/spec/loophp/collection/CollectionSpec.php b/spec/loophp/collection/CollectionSpec.php index 35dc731e7..a6e79ec56 100644 --- a/spec/loophp/collection/CollectionSpec.php +++ b/spec/loophp/collection/CollectionSpec.php @@ -28,7 +28,6 @@ use PhpSpec\ObjectBehavior; use stdClass; use function gettype; -use const E_USER_DEPRECATED; use const INF; use const PHP_EOL; @@ -1989,9 +1988,25 @@ public function it_can_map(): void ->map($appendBar) ->shouldIterateAs(['1bar', '4bar', '9bar']); - $this::fromIterable(range(1, 3)) - ->map($square, $toString) - ->shouldIterateAs(['1', '4', '9']); + $nonStandardInput = static function (): Generator { + yield ['a'] => 1; + + yield ['b'] => 2; + + yield ['a'] => 3; + }; + + $expected = static function (): Generator { + yield ['a'] => 1; + + yield ['b'] => 4; + + yield ['a'] => 9; + }; + + $this::fromIterable($nonStandardInput()) + ->map(static fn (int $value): int => $value ** 2) + ->shouldIterateAs($expected()); } public function it_can_mapN(): void @@ -3853,16 +3868,6 @@ public function it_is_initializable(): void $this->shouldHaveType(Collection::class); } - public function it_shows_deprecation_for_map_multiple_callbacks(): void - { - $square = static fn (int $a): int => $a ** 2; - $toString = static fn (int $a): string => (string) $a; - - $this::fromIterable(range(1, 3)) - ->map($square, $toString) - ->shouldTrigger(E_USER_DEPRECATED)->during('all'); - } - public function let(): void { $this->beConstructedThrough('empty'); diff --git a/src/Collection.php b/src/Collection.php index cc277c655..2fdf6cc31 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -600,9 +600,9 @@ public function lines(): CollectionInterface return new self(Lines::of(), $this->getIterator()); } - public function map(callable ...$callbacks): CollectionInterface + public function map(callable $callback): CollectionInterface { - return new self(Map::of()(...$callbacks), $this->getIterator()); + return new self(Map::of()($callback), $this->getIterator()); } public function mapN(callable ...$callbacks): CollectionInterface diff --git a/src/Contract/Operation/Mapable.php b/src/Contract/Operation/Mapable.php index f3bf23f9c..15092a4a2 100644 --- a/src/Contract/Operation/Mapable.php +++ b/src/Contract/Operation/Mapable.php @@ -19,15 +19,13 @@ interface Mapable { /** - * Apply one or more callbacks to a collection and use the return value. - * Usage with multiple callbacks is deprecated and will be removed in a future major version. - * Use mapN instead for multiple callbacks. + * Apply a single callback to every item of a collection and use the return value. * * @template V * - * @param callable(T, TKey, Iterator): V ...$callbacks + * @param callable(T, TKey, Iterator): V $callback * * @return Collection */ - public function map(callable ...$callbacks): Collection; + public function map(callable $callback): Collection; } diff --git a/src/Operation/Map.php b/src/Operation/Map.php index 6aab70ec2..e810113b2 100644 --- a/src/Operation/Map.php +++ b/src/Operation/Map.php @@ -13,10 +13,6 @@ use Generator; use Iterator; -use function count; - -use const E_USER_DEPRECATED; - /** * @immutable * @@ -30,45 +26,23 @@ final class Map extends AbstractOperation /** * @pure * - * @return Closure(callable(T, TKey, Iterator): T ...): Closure(Iterator): Generator + * @return Closure(callable(T, TKey, Iterator): T): Closure(Iterator): Generator */ public function __invoke(): Closure { return /** - * @param callable(T, TKey, Iterator): T ...$callbacks + * @param callable(T, TKey, Iterator): T $callback */ - static fn (callable ...$callbacks): Closure => + static fn (callable $callback): Closure => /** * @param Iterator $iterator * * @return Generator */ - static function (Iterator $iterator) use ($callbacks): Generator { - if (count($callbacks) > 1) { - @trigger_error( - 'Using `Map` with multiple callbacks is deprecated, and will be removed in a future major version; use `MapN` instead.', - E_USER_DEPRECATED - ); - } - - $callbackFactory = - /** - * @param TKey $key - * - * @return Closure(T, callable(T, TKey, Iterator): T): T - */ - static fn ($key): Closure => - /** - * @param T $carry - * @param callable(T, TKey, Iterator): T $callback - * - * @return T - */ - static fn ($carry, callable $callback) => $callback($carry, $key, $iterator); - + static function (Iterator $iterator) use ($callback): Generator { foreach ($iterator as $key => $value) { - yield $key => array_reduce($callbacks, $callbackFactory($key), $value); + yield $key => $callback($value, $key, $iterator); } }; } diff --git a/tests/static-analysis/map.php b/tests/static-analysis/map.php index 288f4c38e..6fa44644d 100644 --- a/tests/static-analysis/map.php +++ b/tests/static-analysis/map.php @@ -68,17 +68,4 @@ function map_checkMapClass(CollectionInterface $collection): void /** @psalm-suppress InvalidScalarArgument @phpstan-ignore-next-line */ map_checkListInt(Collection::fromIterable(['foo' => 'bar'])->map($square)); /** @psalm-suppress InvalidScalarArgument @phpstan-ignore-next-line */ -map_checkListString(Collection::fromIterable(['foo' => 'bar'])->map($square, $toString)); -/** @psalm-suppress InvalidScalarArgument @phpstan-ignore-next-line */ map_checkMapString(Collection::fromIterable([1, 2, 3])->map($appendBar)); -/** @psalm-suppress InvalidArgument, InvalidScalarArgument @phpstan-ignore-next-line */ -map_checkMapClass(Collection::fromIterable([1, 2, 3])->map($appendBar, $toClass)); - -// VALID failures due to usage with multiple callbacks, which cannot be properly typed -// `mapN` should be used instead for these use cases, which is more lenient due to `mixed` type hints - -/** @psalm-suppress InvalidScalarArgument @phpstan-ignore-next-line */ -map_checkListString(Collection::fromIterable([1, 2, 3])->map($square, $toString)); - -/** @psalm-suppress InvalidArgument @phpstan-ignore-next-line */ -map_checkMapClass(Collection::fromIterable(['foo' => 'bar', 'baz' => 'bar'])->map($appendBar, $toClass));