Before v5 all data structures and most function was pure.
Since v5 @psalm-pure and @psalm-immutable has been removed.
It has many false positives, and it's to difficult use in the real applications.
Some examples with useful code (but with false positives):
Discussion of the problem: vimeo/psalm#8116
This code is invalid since v5:
/**
* @param ArrayList<int> $list
* @return ArrayList<int>
* @psalm-pure
*/
function pureFn(ArrayList $list): ArrayList
{
// ERROR: ImpureMethodCall
return $list->map(fn($i) => $i + 2);
}Removing @psalm-pure from the pureFn fix that problem.
- All collection functions with
$callback/$predicateparams does not allow key as second parameter anymore. To use key in the map, filter and other collection functions use *KV combinators. Each collection function with$callback/$predicatehas *KV version:
- \Fp\Collection\map(fn($value, $key) => new Row(id: $key, data: $value));
+ \Fp\Collection\mapKV(fn($key, $value) => new Row(id: $key, data: $value));- Parameter
$preserveKeysofFp\Collection\filterhas been removed. Type of input array will be preserved:
- \Fp\Collection\filter(['a' => 1, 'b' => 2], fn($value) => $value !== 1, preserveKeys: true); // result is ['b' => 2]
+ \Fp\Collection\filter(['a' => 1, 'b' => 2], fn($value) => $value !== 1); // result is ['b' => 2]
- \Fp\Collection\filter([1, 2], fn($value) => $value !== 1, preserveKeys: true); // result is [2]
+ \Fp\Collection\filter([1, 2], fn($value) => $value !== 1); // result is [2]Fp\Collection\existsOfhas been removed. UseFp\Collection\existsinstead:
- \Fp\Collection\existsOf($collection, Foo::class)
+ \Fp\Collection\exists($collection, fn(mixed $i) => $i instanceof Foo);Fp\Collection\everyOfhas been removed. UseFp\Collection\everyinstead:
- \Fp\Collection\everyOf($collection, Foo::class)
+ \Fp\Collection\every($collection, fn(mixed $i) => $i instanceof Foo);Fp\Collection\firstOfhas been removed. UseFp\Collection\firstMapandFp\Evidence\of:
- \Fp\Collection\firstOf($collection, Foo::class)
+ \Fp\Collection\firstMap($collection, of(Foo::class));Fp\Collection\lastOfhas been removed. UseFp\Collection\lastMapandFp\Evidence\of:
- \Fp\Collection\lastOf($collection, Foo::class)
+ \Fp\Collection\lastMap($collection, of(Foo::class));Fp\Collection\filterOfhas been removed. UseFp\Collection\filterMapandFp\Evidence\of:
- \Fp\Collection\filterOf($collection, Foo::class)
+ \Fp\Collection\filterMap($collection, of(Foo::class));Fp\Collection\everyMaphas been removed. UseFp\Collection\traverseOption:
- \Fp\Collection\everyMap($collection, fn($i) => Option::when($i % 2, fn() => $i));
+ \Fp\Collection\traverseOption($collection, fn($i) => Option::when($i % 2, fn() => $i));Fp\Collection\reducehas been removed. UseFp\Collection\fold:
- \Fp\Collection\reduce($collection, fn($acc, $cur) => $acc + $cur)->getOrElse(0);
+ \Fp\Collection\fold($collection, 0)(fn($acc, $cur) => $acc + $cur);Fp\Collection\partitionOfhas been removed. UseFp\Collection\partitionT:
- \Fp\Collection\partitionOf($collection, Foo::class, Bar::class);
+ \Fp\Collection\partitionT($collection, fn($i) => $i instanceof Foo, fn($i) => $i instanceof Bar);Fp\Evidence\proveListOfhas been removed. UseFp\Evidence\proveListandFp\Evidence\of:
- \Fp\Evidence\proveListOf(getMixed(), Foo::class);
+ \Fp\Evidence\proveList(getMixed(), of(Foo::class));Fp\Evidence\proveNonEmptyListOfhas been removed. UseFp\Evidence\proveNonEmptyListandFp\Evidence\of:
- \Fp\Evidence\proveNonEmptyListOf(getMixed(), Foo::class);
+ \Fp\Evidence\proveNonEmptyList(getMixed(), of(Foo::class));Fp\Evidence\proveArrayOfhas been removed. UseFp\Evidence\proveListandFp\Evidence\of:
- \Fp\Evidence\proveArrayOf(getMixed(), Foo::class);
+ \Fp\Evidence\proveArray(getMixed(), vType: of(Foo::class));Fp\Evidence\proveNonEmptyArrayOfhas been removed. UseFp\Evidence\proveNonEmptyListandFp\Evidence\of:
- \Fp\Evidence\proveNonEmptyArrayOf(getMixed(), Foo::class);
+ \Fp\Evidence\proveNonEmptyArray(getMixed(), vType: of(Foo::class));Fp\Json\jsonDecodemoved toFp\Util\jsonDecode:
- \Fp\Json\jsonDecode('[1,2,3]');
+ \Fp\Util\jsonDecode('[1,2,3]');Fp\String\regExpMatchmoved toFp\Util\regExpMatch:
- \Fp\String\regExpMatch('/[a-z]+(?<num>[0-9]+)/', 'aa1123');
+ \Fp\Util\regExpMatch('/[a-z]+(?<num>[0-9]+)/', 'aa1123');Fp\Reflection\getReflectionClasshas been removed without replacement.Fp\Reflection\getReflectionPropertyhas been removed without replacement.
Fp\Functional\Option\Option::filterOfhas been removed. UseFp\Functional\Option\Option::flatMapandFp\Evidence\of:
- $option->filterOf(Foo::class);
+ $option->flatMap(of(Foo::class));Fp\Functional\Option\Option::getOrThrowhas been removed. UseFp\Functional\Option\Option::getOrCall:
- $option->getOrThrow(fn() => new RuntimeExeption());
+ $option->getOrCall(fn() => throw new RuntimeExeption());Fp\Functional\Option\Option::isEmptyhas been removed. UseFp\Functional\Option\Option::isNone:
- $option->isEmpty();
+ $option->isNone();Fp\Functional\Option\Option::isNonEmptyhas been removed. UseFp\Functional\Option\Option::isSome:
- $option->isNonEmpty();
+ $option->isSome();Fp\Functional\Option\Option::condhas been removed. UseFp\Functional\Option\Option::when:
- \Fp\Functional\Option\Option::cond(getTrue(), doSomething());
+ \Fp\Functional\Option\Option::when(getTrue(), fn() => doSomething());Fp\Functional\Option\Option::unlesshas been removed. UseFp\Functional\Option\Option::when:
- \Fp\Functional\Option\Option::unless(getFalse(), fn() => doSomething());
+ \Fp\Functional\Option\Option::when(!getFalse(), fn() => doSomething());Fp\Functional\Option\Option::condLazyhas been removed. UseFp\Functional\Option\Option::when:
- \Fp\Functional\Option\Option::condLazy(getTrue(), fn() => doSomething());
+ \Fp\Functional\Option\Option::when(getTrue(), fn() => doSomething());- Order of
Fp\Functional\Option\Option::foldparams was changed:
- $option->fold(fn($some) => doSomethingWhenSome($some) fn() => doSomethingWhenNone());
+ $option->fold(fn() => doSomethingWhenNone(), fn($some) => doSomethingWhenSome($some));Fp\Functional\Either\Either::condLazyhas been removed. UseFp\Functional\Either\Either::when:
- \Fp\Functional\Either\Either::condLazy(getBool(), fn() => trueToRight(), fn() => falseToLeft());
+ \Fp\Functional\Either\Either::when(getBool(), fn() => trueToRight(), fn() => falseToLeft());Fp\Functional\Either\Either::condhas been removed. UseFp\Functional\Either\Either::when:
- \Fp\Functional\Either\Either::cond(getBool(), trueToRight(), falseToLeft());
+ \Fp\Functional\Either\Either::when(getBool(), fn() => trueToRight(), fn() => falseToLeft());- Order of
Fp\Functional\Either\Either::foldparams has been changed:
- $either->fold(fn($right) => doSomethingWhenRight($right), fn($left) => doSomethingWhenLeft($left));
+ $either->fold(fn($left) => doSomethingWhenLeft($left), fn($right) => doSomethingWhenRight($right));Fp\Collections\Seq::uniquehas been removed. UseFp\Collections\Seq::uniqueByinstead:
- $seq->unique(fn(Foo $foo) => $foo->a);
+ $seq->uniqueBy(fn(Foo $foo) => $foo->a);Fp\Collections\Entryhas been removed. To use key in the map, filter and otherFp\Collections\Mapoperations use *KV combinators:
- $map->map(fn(Entry $kv) => new Row(id: $kv->key, data: $kv->value));
+ $map->mapKV(fn(string $key, array $row) => new Row(id: $key, data: $row));Each Fp\Collections\Map operation has *KV version.
- Iteration with foreach has been changed:
- foreach($map as [$k, $v]) {}
+ foreach($map as $k => $v) {}Fp\Collections\Map::toAssocArrayhas been removed. UseFp\Collections\Map::toArrayinstead:
- $map->toAssocArray()->getOrElse([]);
+ $map->toArray();Fp\Collections\Map::toArray has @psalm-if-this-is annotation. It impossibly to call this method if Map key is not array-key subtype.
Fp\Collections\Map::mapKeyshas been removed. UseFp\Collections\Map::reindexinstead:
- $map->mapKeys(fn(Entry $kv) => $kv->value->a);
+ $map->reindex(fn(Foo $foo) => $foo->a);- Alias
Fp\Collections\Map::mapValueshas been removed. UseFp\Collections\Map::mapinstead:
- $map->mapValues(fn(Entry $kv) => $kv->value->a);
+ $map->map(fn(Foo $foo) => $foo->a);- Method
Fp\Collections\Map::updatedhas been renamed toFp\Collections\Map::appended.
- $map->updated($key, $value);
+ $map->appended($key, $value);Fp\Collections\Set::updatedhas been removed. UseFp\Collections\Set::appended:
- $set->updated(new Foo(a: 42));
+ $set->appended(new Foo(a: 42));Fp\Streams\Stream::toAssocArrayhas been removed. UseFp\Streams\Stream::toArrayinstead:
- $stream->toAssocArray();
+ $stream->toArray();Fp\Streams\Stream::repeatNhas been removed. UseFp\Streams\Stream::repeatwith$timesparameter:
- $stream->repeatN(2);
+ $stream->repeat(2);Fp\Streams\Stream::sortedhas been removed. This method was hide all elements loading to the memory. Alternative:
+ $stream->sorted(fn($l, $r) => $l <=> $r);
+ $stream->toArrayList()->sorted(fn($l, $r) => $l <=> $r)->toStream();- Method
filterOfhas been removed. UsefilterMapmethod andFp\Evidence\offunction:
- $seq->filterOf(Foo::class);
+ $seq->filterMap(of(Foo::class));- Method
firstOfhas been removed. UsefirstMapmethod andFp\Evidence\offunction:
- $seq->firstOf(Foo::class);
+ $seq->firstMap(of(Foo::class));- Method
lastOfhas been removed. UselastMapmethod andFp\Evidence\offunction:
- $seq->lastOf(Foo::class);
+ $seq->lastMap(of(Foo::class));- Method
reducehas been removed. Usefoldmethod:
- $seq->reduce(fn($acc, $cur) => $acc + $cur)->getOrElse(0);
+ $seq->fold(0)(fn($acc, $cur) => $acc + $cur);- Method
everyMaphas been removed. UsetraverseOptionmethod:
- $seq->everyMap(fn($i) => Option::when(is_numeric($i), fn() => (int) $i));
+ $seq->traverseOption(fn($i) => Option::when(is_numeric($i), fn() => (int) $i));- Method
existsOfhas been removed. Useexistsmethod with predicate:
- $seq->existsOf(Foo::class);
+ $seq->exists(fn($i) => $i instanceof Foo);- Method
everyOfhas been removed. Useeverymethod with predicate:
- $seq->everyOf(Foo::class);
+ $seq->every(fn($i) => $i instanceof Foo);- Signature of
toHashMapmethod has been changed:
- $seq->toHashMap($i => [$i->key, $i]);
+ $seq->toHashMap();Method toHashMap now have @psalm-if-this-is annotation.
- Signature of
toArraymethod has been changed:
- $seq->toArray();
+ $seq->toList();Method toArray now have @psalm-if-this-is annotation and return array<TKO, TVO> instead list<TV>.
- Fp\Functional\Validated\Validated
- Fp\Functional\Semigroup\Semigroup
- Fp\Functional\Monoid\Monoid