PHP code example of fp4php / functional-psalm-plugin
1. Go to this page and download the library: Download fp4php/functional-psalm-plugin library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
fp4php / functional-psalm-plugin example snippets
declare(strict_types=1);
use Fp\Functional\Option\Option;
/**
* @return Option<int|string>
*/
function getOption(): Option
{
// ...
}
// Narrowed to Option<string>
/** @psalm-trace $result */
$result = getOption()->filter(fn($value) => is_string($value));
declare(strict_types=1);
use Fp\Collections\ArrayList;
/**
* @return ArrayList<int|string>
*/
function getArrayList(): ArrayList
{
// ...
}
// Narrowed to ArrayList<string>
/** @psalm-trace $result */
$result = getArrayList()->filter(fn($value) => is_string($value));
declare(strict_types=1);
use TypeError;
use ValueError;
use Fp\Functional\Either\Either;
/**
* @return Either<ValueError, int|string>
*/
function getEither(): Either
{
// ...
}
// Narrowed to Either<TypeError|ValueError, string>
getEither()->filterOrElse(
fn($value) => is_string($value),
fn() => new TypeError('Is not string'),
);
declare(strict_types=1);
use function Fp\Collection\filter;
/**
* @return list<int|string>
*/
function getList(): array
{
// ...
}
// Narrowed to list<string>
filter(getList(), fn($value) => is_string($value));
declare(strict_types=1);
use function Fp\Collection\first;
use function Fp\Collection\last;
/**
* @return list<int|string>
*/
function getList(): array
{
// ...
}
// Narrowed to Option<string>
first(getList(), fn($value) => is_string($value));
// Narrowed to Option<int>
last(getList(), fn($value) => is_int($value));
declare(strict_types=1);
use function Fp\Collection\filter;
/**
* @return list<int|string>
*/
function getList(): array
{
// ...
}
// Narrowed to list<string>
filter(getList(), is_string(...));
use Tests\Mock\Foo;
use function Fp\Callable\ctor;
// Psalm knows that ctor(Foo::class) is Closure(int, bool, bool): Foo
test(ctor(Foo::class));
/**
* @param Closure(int, bool, bool): Foo $makeFoo
*/
function test(Closure $makeFoo): void
{
print_r($makeFoo(42, true, false));
print_r(PHP_EOL);
}
use Fp\Functional\Option\Option;
use function Fp\Collection\sequenceOption;
use function Fp\Collection\sequenceOptionT;
function getFoo(int $id): Option
{
// ...
}
function getBar(int $id): Option
{
// ...
}
/**
* @return Option<array{foo: Foo, bar: Bar}>
*/
function sequenceOptionShapeExample(int $id): Option
{
// Inferred type is: Option<array{foo: Foo, bar: Bar}> not Option<array<'foo'|'bar', Foo|Bar>>
return sequenceOption([
'foo' => getFoo($id),
'bar' => getBar($id),
]);
}
/**
* @return Option<array{Foo, Bar}>
*/
function sequenceOptionTupleExample(int $id): Option
{
// Inferred type is: Option<array{Foo, Bar}> not Option<list<Foo|Bar>>
return sequenceOptionT(getFoo($id), getBar($id));
}
declare(strict_types=1);
use Fp\Functional\Option\Option;
use Tests\Mock\Foo;
/**
* @param Option<array{int, bool}> $maybeData
* @return Option<Foo>
*/
function test(Option $maybeData): Option
{
/*
* ERROR: IfThisIsMismatch
* Object must be type of Option<array{int, bool, bool}>, actual type Option<array{int, bool}>
*/
return $maybeData->mapN(fn(int $a, bool $b, bool $c) => new Foo($a, $b, $c));
}
use Fp\Functional\Option\Option;
function getIntOrString(): int|string
{
// ...
}
Option::do(function() {
$value = getIntOrString();
yield proveTrue(is_int($value));
// here $value narrowed to int from int|string
});
use Fp\Collections\HashSet;
use Fp\Collections\ArrayList;
use Fp\Functional\Either\Either;
use Fp\Functional\Separated\Separated;
/**
* @param Separated<ArrayList<int>, ArrayList<string>> $separated
* @return Either<ArrayList<int>, ArrayList<string>>
*/
function separatedArrayListToEither(Separated $separated): Either
{
return $separated->toEither();
}
/**
* @param Separated<HashSet<int>, HashSet<string>> $separated
* @return Either<HashSet<int>, HashSet<string>>
*/
function separatedHashSetToEither(Separated $separated): Either
{
return $separated->toEither();
}
declare(strict_types=1);
use Tests\Mock\Foo;
use Tests\Mock\Bar;
use Tests\Mock\Baz;
use function Fp\Collection\partitionT;
/**
* @param list<Foo|Bar|Baz> $list
* @return array{list<Foo>, list<Bar>, list<Baz>}
*/
function testExhaustiveInference(array $list): array
{
return partitionT($list, fn($i) => $i instanceof Foo, fn($i) => $i instanceof Bar);
}
declare(strict_types=1);
use function Fp\Collection\filterNotNull;
/**
* @param array{name: string, age: int|null} $shape
* @return array{name: string, age?: int}
*/
function example(array $shape): array
{
return filterNotNull($shape);
}