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
/$predicate
params 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
/$predicate
has *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
$preserveKeys
ofFp\Collection\filter
has 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\existsOf
has been removed. UseFp\Collection\exists
instead:
- \Fp\Collection\existsOf($collection, Foo::class)
+ \Fp\Collection\exists($collection, fn(mixed $i) => $i instanceof Foo);
Fp\Collection\everyOf
has been removed. UseFp\Collection\every
instead:
- \Fp\Collection\everyOf($collection, Foo::class)
+ \Fp\Collection\every($collection, fn(mixed $i) => $i instanceof Foo);
Fp\Collection\firstOf
has been removed. UseFp\Collection\firstMap
andFp\Evidence\of
:
- \Fp\Collection\firstOf($collection, Foo::class)
+ \Fp\Collection\firstMap($collection, of(Foo::class));
Fp\Collection\lastOf
has been removed. UseFp\Collection\lastMap
andFp\Evidence\of
:
- \Fp\Collection\lastOf($collection, Foo::class)
+ \Fp\Collection\lastMap($collection, of(Foo::class));
Fp\Collection\filterOf
has been removed. UseFp\Collection\filterMap
andFp\Evidence\of
:
- \Fp\Collection\filterOf($collection, Foo::class)
+ \Fp\Collection\filterMap($collection, of(Foo::class));
Fp\Collection\everyMap
has 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\reduce
has 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\partitionOf
has 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\proveListOf
has been removed. UseFp\Evidence\proveList
andFp\Evidence\of
:
- \Fp\Evidence\proveListOf(getMixed(), Foo::class);
+ \Fp\Evidence\proveList(getMixed(), of(Foo::class));
Fp\Evidence\proveNonEmptyListOf
has been removed. UseFp\Evidence\proveNonEmptyList
andFp\Evidence\of
:
- \Fp\Evidence\proveNonEmptyListOf(getMixed(), Foo::class);
+ \Fp\Evidence\proveNonEmptyList(getMixed(), of(Foo::class));
Fp\Evidence\proveArrayOf
has been removed. UseFp\Evidence\proveList
andFp\Evidence\of
:
- \Fp\Evidence\proveArrayOf(getMixed(), Foo::class);
+ \Fp\Evidence\proveArray(getMixed(), vType: of(Foo::class));
Fp\Evidence\proveNonEmptyArrayOf
has been removed. UseFp\Evidence\proveNonEmptyList
andFp\Evidence\of
:
- \Fp\Evidence\proveNonEmptyArrayOf(getMixed(), Foo::class);
+ \Fp\Evidence\proveNonEmptyArray(getMixed(), vType: of(Foo::class));
Fp\Json\jsonDecode
moved toFp\Util\jsonDecode
:
- \Fp\Json\jsonDecode('[1,2,3]');
+ \Fp\Util\jsonDecode('[1,2,3]');
Fp\String\regExpMatch
moved toFp\Util\regExpMatch
:
- \Fp\String\regExpMatch('/[a-z]+(?<num>[0-9]+)/', 'aa1123');
+ \Fp\Util\regExpMatch('/[a-z]+(?<num>[0-9]+)/', 'aa1123');
Fp\Reflection\getReflectionClass
has been removed without replacement.Fp\Reflection\getReflectionProperty
has been removed without replacement.
Fp\Functional\Option\Option::filterOf
has been removed. UseFp\Functional\Option\Option::flatMap
andFp\Evidence\of
:
- $option->filterOf(Foo::class);
+ $option->flatMap(of(Foo::class));
Fp\Functional\Option\Option::getOrThrow
has been removed. UseFp\Functional\Option\Option::getOrCall
:
- $option->getOrThrow(fn() => new RuntimeExeption());
+ $option->getOrCall(fn() => throw new RuntimeExeption());
Fp\Functional\Option\Option::isEmpty
has been removed. UseFp\Functional\Option\Option::isNone
:
- $option->isEmpty();
+ $option->isNone();
Fp\Functional\Option\Option::isNonEmpty
has been removed. UseFp\Functional\Option\Option::isSome
:
- $option->isNonEmpty();
+ $option->isSome();
Fp\Functional\Option\Option::cond
has 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::unless
has 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::condLazy
has 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::fold
params was changed:
- $option->fold(fn($some) => doSomethingWhenSome($some) fn() => doSomethingWhenNone());
+ $option->fold(fn() => doSomethingWhenNone(), fn($some) => doSomethingWhenSome($some));
Fp\Functional\Either\Either::condLazy
has 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::cond
has 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::fold
params 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::unique
has been removed. UseFp\Collections\Seq::uniqueBy
instead:
- $seq->unique(fn(Foo $foo) => $foo->a);
+ $seq->uniqueBy(fn(Foo $foo) => $foo->a);
Fp\Collections\Entry
has been removed. To use key in the map, filter and otherFp\Collections\Map
operations 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::toAssocArray
has been removed. UseFp\Collections\Map::toArray
instead:
- $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::mapKeys
has been removed. UseFp\Collections\Map::reindex
instead:
- $map->mapKeys(fn(Entry $kv) => $kv->value->a);
+ $map->reindex(fn(Foo $foo) => $foo->a);
- Alias
Fp\Collections\Map::mapValues
has been removed. UseFp\Collections\Map::map
instead:
- $map->mapValues(fn(Entry $kv) => $kv->value->a);
+ $map->map(fn(Foo $foo) => $foo->a);
- Method
Fp\Collections\Map::updated
has been renamed toFp\Collections\Map::appended
.
- $map->updated($key, $value);
+ $map->appended($key, $value);
Fp\Collections\Set::updated
has been removed. UseFp\Collections\Set::appended
:
- $set->updated(new Foo(a: 42));
+ $set->appended(new Foo(a: 42));
Fp\Streams\Stream::toAssocArray
has been removed. UseFp\Streams\Stream::toArray
instead:
- $stream->toAssocArray();
+ $stream->toArray();
Fp\Streams\Stream::repeatN
has been removed. UseFp\Streams\Stream::repeat
with$times
parameter:
- $stream->repeatN(2);
+ $stream->repeat(2);
Fp\Streams\Stream::sorted
has 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
filterOf
has been removed. UsefilterMap
method andFp\Evidence\of
function:
- $seq->filterOf(Foo::class);
+ $seq->filterMap(of(Foo::class));
- Method
firstOf
has been removed. UsefirstMap
method andFp\Evidence\of
function:
- $seq->firstOf(Foo::class);
+ $seq->firstMap(of(Foo::class));
- Method
lastOf
has been removed. UselastMap
method andFp\Evidence\of
function:
- $seq->lastOf(Foo::class);
+ $seq->lastMap(of(Foo::class));
- Method
reduce
has been removed. Usefold
method:
- $seq->reduce(fn($acc, $cur) => $acc + $cur)->getOrElse(0);
+ $seq->fold(0)(fn($acc, $cur) => $acc + $cur);
- Method
everyMap
has been removed. UsetraverseOption
method:
- $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
existsOf
has been removed. Useexists
method with predicate:
- $seq->existsOf(Foo::class);
+ $seq->exists(fn($i) => $i instanceof Foo);
- Method
everyOf
has been removed. Useevery
method with predicate:
- $seq->everyOf(Foo::class);
+ $seq->every(fn($i) => $i instanceof Foo);
- Signature of
toHashMap
method has been changed:
- $seq->toHashMap($i => [$i->key, $i]);
+ $seq->toHashMap();
Method toHashMap
now have @psalm-if-this-is
annotation.
- Signature of
toArray
method 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