10
GitHub - whsv26/functional: PHP Functional Programming library. Monads, common u...
source link: https://github.com/whsv26/functional
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Functional PHP
PHP Functional Programming library. Monads and common use functions.
Documentation
Installation
Composer
$ composer require whsv26/functional
Enable psalm plugin (optional)
To improve type inference for particular functions
$ vendor/bin/psalm-plugin enable Fp\\Psalm\\FunctionalPlugin
Examples
- Type assertions with Option monad
/** * Inferred type is Option<Foo> */ $maybeFooMaybeNot = Option::do(function() use ($untrusted) { $notNull = yield Option::fromNullable($untrusted); yield proveTrue(is_array($notNull)); // Inferred type is array<array-key, mixed> $list = yield proveList($notNull); // Inferred type is list<mixed> $nonEmptyList = yield proveNonEmptyList($list); // Inferred type is non-empty-list<mixed> $nonEmptyListOfFoo = yield proveNonEmptyListOf($nonEmptyList, Foo::class); // Inferred type is non-empty-list<Foo> $firstFoo = $nonEmptyListOfFoo[0]; // Inferred type is Foo return $firstFoo; // I'm sure it's Foo object }); /** * Inferred type is Foo */ $foo = $maybeFooMaybeNot->getOrCall(fn() => new Foo(0))
- Type safety
/** * Inferred type is NonEmptyLinkedList<1|2|3> */ $collection = NonEmptyLinkedList::collectNonEmpty([1, 2, 3]); /** * Inferred type is NonEmptyLinkedList<int> * * Literal types are dropped after map transformation, * but NonEmpty collection prefix has been kept */ $mappedCollection = $collection->map(fn($elem) => $elem - 1); /** * Inferred type is LinkedList<positive-int> * NonEmpty prefix has been dropped */ $filteredCollection = $mappedCollection->filter(fn(int $elem) => $elem > 0);
$source = [new Foo(1), null, new Bar(2)]; /** * Inferred type is ArrayList<Foo|Bar> * Null type was removed * NonEmpty prefix was removed */ $withoutNulls = NonEmptyArrayList::collectNonEmpty($source)->filterNotNull(); /** * Inferred type is ArrayList<Foo> * Bar type was removed */ $onlyFoos = $withoutNulls->filter(fn($elem) => $elem instanceof Foo);
- Covariance
class User {} class Admin extends User {} /** * @param NonEmptyCollection<User> $collection */ function acceptUsers(NonEmptyCollection $collection): void {} /** * @var NonEmptyLinkedList<Admin> $collection */ $collection = NonEmptyLinkedList::collectNonEmpty([new Admin()]); /** * You can pass collection of admins instead of users * Because of covariant template parameter */ acceptUsers($collection);
- Immutability
$originalCollection = LinkedList::collect([1, 2, 3]); /** * $originalCollection won't be changed */ $prependedCollection = $originalCollection->prepended(0); /** * $prependedCollection won't be changed */ $mappedCollection = $prependedCollection->map(fn(int $elem) => $elem + 1);
- Null safety
/** * @var Collection<int> $emptyCollection */ $emptyCollection = getEmptyCollection(); $resultWithDefaultValue = $emptyCollection ->reduce(fn(int $accumulator, int $element) => $accumulator + $element) ->getOrElse(0); /** * @return Option<float> */ function div(int $a, int $b): Option { return 0 === $b ? Option::none() : Option::some($a / $b) } /** * It's possible there is no first collection element above zero * In this case the execution will short circuit (stop) * And no Null Pointer Exception will be thrown */ $emptyCollection ->first(fn(int $elem) => $elem > 0) ->map(fn(int $elem) => $elem + 1) ->flatMap(fn(int $elem) => div($elem, $elem - 1)) ->getOrElse(0)
Contribution
Build documentation
- Install dependencies
$ sudo apt install pandoc
- Generate doc from src
$ make
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK