### Install Functional PHP using Composer Source: https://github.com/fp4php/functional/blob/master/README.md This command installs the fp4php/functional library using Composer, the dependency manager for PHP. Ensure Composer is installed and accessible in your environment. ```console composer require fp4php/functional ``` -------------------------------- ### Build Documentation with Make and Pandoc Source: https://github.com/fp4php/functional/blob/master/README.md Instructions for building documentation for the fp4php/functional project. It requires installing Pandoc and then running the 'make' command. ```console $ sudo apt install pandoc ``` ```console $ make ``` -------------------------------- ### Do-Notation for Simplified Monadic Chains in PHP Source: https://github.com/fp4php/functional/blob/master/doc/Monads.md Do-notation provides syntactic sugar to simplify long chains of monadic operations, making the code more readable. This example demonstrates how to use Option::do to achieve the same result as the previous Option monad example, but with a more imperative-like syntax. ```php */ function getUserById(int $id): Option {} /** * @return Option */ function getUserFirstOrder(User $user): Option {} /** * @return Option */ function getOrderTrackNumber(Order $order): Option {} /** * @return Option */ function getTrackingStatus(TrackingNumber $trackingNumber): Option {} /** * @var string $status */ $status = Option::do(function () { $user = yield getUserById(654); $order = yield getUserFirstOrder($user); $trackNumber = yield getOrderTrackNumber($order); return yield getTrackingStatus($trackNumber); })->getOrElse('no status info'); ?> ``` -------------------------------- ### Install New Psalm Plugin with Composer Source: https://github.com/fp4php/functional/blob/master/UPGRADING-v6.md This command installs the new fp4php/functional-psalm-plugin as a development dependency using Composer. ```shell composer require --dev fp4php/functional-psalm-plugin ``` -------------------------------- ### Chaining Filters with Option Monad in PHP Source: https://github.com/fp4php/functional/blob/master/src/Doc/Md/Monads/4_Examples.md Illustrates how to build complex filters by chaining small Option-based blocks in PHP. This approach allows for sequential filtering and transformation of data, returning an Option of the final result. It utilizes Fp\Functional\Option\Option and Fp\Collection\head. ```php */ function getUnionTypeParam(Union $union): Option { return Option::do(function () use ($union) { $atomics = $union->getAtomicTypes(); yield proveTrue(1 === count($atomics)); $atomic = yield head($atomics); return yield self::filterTIterableTypeParam($atomic) ->orElse(fn() => self::filterTArrayTypeParam($atomic)) ->orElse(fn() => self::filterTListTypeParam($atomic)) ->orElse(fn() => self::filterTGenericObjectTypeParam($atomic)) ->orElse(fn() => self::filterTKeyedArrayTypeParam($atomic)); }); } /** * @return Option */ function filterTIterableTypeParam(Atomic $atomic): Option { return Option::some($atomic) ->filter(fn(Atomic $a) => $a instanceof TIterable) ->map(fn(TIterable $a) => $a->type_params[1]); } /** * @return Option */ function filterTArrayTypeParam(Atomic $atomic): Option { return Option::some($atomic) ->filter(fn(Atomic $a) => $a instanceof TArray) ->map(fn(TArray $a) => $a->type_params[1]); } /** * @return Option */ function filterTListTypeParam(Atomic $atomic): Option { return Option::some($atomic) ->filter(fn(Atomic $a) => $a instanceof TList) ->map(fn(TList $a) => $a->type_param); } /** * @return Option */ function filterTKeyedArrayTypeParam(Atomic $atomic): Option { return Option::some($atomic) ->filter(fn(Atomic $a) => $a instanceof TKeyedArray) ->map(fn(TKeyedArray $a) => $a->getGenericValueType()); } /** * @return Option */ function filterTGenericObjectTypeParam(Atomic $atomic): Option { return Option::some($atomic) ->filter(fn(Atomic $a) => $a instanceof TGenericObject) ->flatMap(fn(TGenericObject $a) => Option::fromNullable(match (true) { is_subclass_of($a->value, Seq::class) => $a->type_params[0], is_subclass_of($a->value, Set::class) => $a->type_params[0], is_subclass_of($a->value, Map::class) => $a->type_params[1], is_subclass_of($a->value, NonEmptySeq::class) => $a->type_params[0], is_subclass_of($a->value, NonEmptySet::class) => $a->type_params[0], default => null })); } ``` -------------------------------- ### Infer list types from partitionT predicates in PHP Source: https://github.com/fp4php/functional/blob/master/doc/Psalm.md This example demonstrates how the Psalm plugin infers specific list types from the predicates provided to `Fp\Collection\partitionT`. The function `testExhaustiveInference` takes a list of mixed types (`Foo|Bar|Baz`) and partitions it based on instance checks, with the plugin correctly inferring the return type as a tuple of specialized lists. ```php $list * @return array{list, list, list} */ function testExhaustiveInference(array $list): array { return partitionT($list, fn($i) => $i instanceof Foo, fn($i) => $i instanceof Bar); } ``` -------------------------------- ### Replace Collection::everyMap with traverseOption Source: https://github.com/fp4php/functional/blob/master/UPGRADING-v5.md The `everyMap` method has been removed from collections. Use the `traverseOption` method for applying a function that returns an `Option` to each element. ```diff - $seq->everyMap(fn($i) => Option::when(is_numeric($i), fn() => (int) $i)); + $seq->traverseOption(fn($i) => Option::when(is_numeric($i), fn() => (int) $i)); ``` -------------------------------- ### Option BC: Replace isEmpty with isNone Source: https://github.com/fp4php/functional/blob/master/UPGRADING-v5.md The `isEmpty` method on `Fp\Functional\Option\Option` has been removed. Use the `isNone` method to check if an Option is empty. ```php $option->isNone(); ``` -------------------------------- ### Filter Chaining with Option (PHP) Source: https://github.com/fp4php/functional/blob/master/doc/Monads.md Illustrates how to build complex filters by chaining small Option-based blocks. This example shows a function that attempts to extract a specific type parameter from a Union, trying various filtering methods sequentially. ```php */ function getUnionTypeParam(Union $union): Option { return Option::do(function () use ($union) { $atomics = $union->getAtomicTypes(); yield proveTrue(1 === count($atomics)); $atomic = yield head($atomics); return yield self::filterTIterableTypeParam($atomic) ->orElse(fn() => self::filterTArrayTypeParam($atomic)) ->orElse(fn() => self::filterTListTypeParam($atomic)) ->orElse(fn() => self::filterTGenericObjectTypeParam($atomic)) ->orElse(fn() => self::filterTKeyedArrayTypeParam($atomic)); }); } /** * @return Option */ function filterTIterableTypeParam(Atomic $atomic): Option { return Option::some($atomic) ->filter(fn(Atomic $a) => $a instanceof TIterable) ->map(fn(TIterable $a) => $a->type_params[1]); } /** * @return Option */ function filterTArrayTypeParam(Atomic $atomic): Option { return Option::some($atomic) ->filter(fn(Atomic $a) => $a instanceof TArray) ->map(fn(TArray $a) => $a->type_params[1]); } /** * @return Option */ function filterTListTypeParam(Atomic $atomic): Option { return Option::some($atomic) ->filter(fn(Atomic $a) => $a instanceof TList) ->map(fn(TList $a) => $a->type_param); } /** * @return Option */ function filterTKeyedArrayTypeParam(Atomic $atomic): Option { return Option::some($atomic) ->filter(fn(Atomic $a) => $a instanceof TKeyedArray) ->map(fn(TKeyedArray $a) => $a->getGenericValueType()); } /** * @return Option */ function filterTGenericObjectTypeParam(Atomic $atomic): Option { return Option::some($atomic) ->filter(fn(Atomic $a) => $a instanceof TGenericObject) ->flatMap(fn(TGenericObject $a) => Option::fromNullable(match (true) { is_subclass_of($a->value, Seq::class) => $a->type_params[0], is_subclass_of($a->value, Set::class) => $a->type_params[0], is_subclass_of($a->value, Map::class) => $a->type_params[1], is_subclass_of($a->value, NonEmptySeq::class) => $a->type_params[0], is_subclass_of($a->value, NonEmptySet::class) => $a->type_params[0], default => null })); } ``` -------------------------------- ### PHP NonEmptyHashSet: Custom Object Comparison and Operations Source: https://github.com/fp4php/functional/blob/master/doc/Collections.md Demonstrates implementing HashContract for custom object comparison in NonEmptyHashSet. Includes examples of collecting elements, mapping, folding, checking for element containment, and subset operations. ```php a === $that->a && $this->b === $that->b; } public function hashCode(): string { return md5(implode(',', [$this->a, $this->b])); } } $collection = NonEmptyHashSet::collectNonEmpty([ new Foo(1), new Foo(2), new Foo(2), new Foo(3), new Foo(3), new Foo(4), ]); $collection ->map(fn(Foo $elem) => $elem->a) ->fold(0)(fn($acc, $elem) => $acc + $elem); // 10 /** * Check if set contains given element */ $collection(new Foo(2)); // true /** * Check if one set is contained in another set */ $collection->subsetOf( NonEmptyHashSet::collectNonEmpty([ new Foo(1), new Foo(2), new Foo(3), new Foo(4), new Foo(5), new Foo(6), ]), ); // true ``` -------------------------------- ### Interleaving and Folding Streams in PHP Source: https://github.com/fp4php/functional/blob/master/src/Doc/Md/Streams/1_Overview.md Demonstrates interleaving two streams, adding a separator between elements, and then folding the result into a single string. This example illustrates combining multiple streams and aggregating their elements. ```php interleave(Stream::emits([4, 5, 6, 7])) // [1, 4, 2, 5, 3, 6] ->intersperse('+') // [1, '+', 4, '+', 2, '+', 5, '+', 3, '+', 6] ->fold('', fn(string $acc, $cur) => $acc . $cur); // '1+4+2+5+3+6' ``` -------------------------------- ### NonEmptyArrayList: Collecting and Folding Elements in PHP Source: https://github.com/fp4php/functional/blob/master/doc/Collections.md Shows how to use NonEmptyArrayList in PHP to collect elements and perform a fold operation. This example demonstrates creating a non-empty list from an array of Foo objects, mapping to extract integer values, and then summing them up using a fold. ```php map(fn(Foo $elem) => $elem->a) ->fold(0)(fn($acc, $elem) => $acc + $elem); // 10 ``` -------------------------------- ### Create Foo object using ctor function with mapN Source: https://github.com/fp4php/functional/blob/master/src/Doc/Md/Combinators/1_N_combinators.md This example demonstrates an alternative way to use mapN with the Fp\Callable\ctor function to create a Foo object from an Option containing a tuple. The ctor function simplifies the process, especially when dealing with constructors. It requires Fp\Functional\Option\Option and Tests\Mock\Foo. ```php $maybeData * @return Option */ function ctor(Option $maybeData): Option { return $maybeData->mapN(ctor(Foo::class)); } ``` -------------------------------- ### Either BC: Replace condLazy with when Source: https://github.com/fp4php/functional/blob/master/UPGRADING-v5.md The `condLazy` method on `Fp\Functional\Either\Either` has been removed. Use the `when` method, providing a predicate and callables for both true and false outcomes. ```php \Fp\Functional\Either\Either::when(getBool(), fn() => trueToRight(), fn() => falseToLeft()); ``` -------------------------------- ### PHP Do-Notation for Monadic Operations Source: https://context7.com/fp4php/functional/llms.txt Demonstrates the use of Do-Notation in PHP with generators for sequential monadic operations. It supports early exit on failure for Option and Either types and includes examples of type assertions. ```php getStatus(); })->getOrElse('No tracking info'); // Either do-notation with error propagation $result = Either::do(function() { $user = yield validateUser($_POST); // Short-circuits on Left $email = yield validateEmail($user['email']); $saved = yield saveToDatabase($user); return ['id' => $saved->id, 'email' => $email]; }); // Type assertions with do-notation use function Fp\Evidence\proveTrue; use function Fp\Evidence\proveNonEmptyList; use function Fp\Evidence\of; $validated = Option::do(function() use ($untrusted) { $notNull = yield Option::fromNullable($untrusted); $list = yield proveNonEmptyList($notNull, of(User::class)); yield proveTrue(count($list) <= 100); // Assert condition return $list; }); ``` -------------------------------- ### PHP Evidence: Replace proveNonEmptyListOf with proveNonEmptyList and of in PHP Source: https://github.com/fp4php/functional/blob/master/UPGRADING-v5.md The `Fp\Evidence\proveNonEmptyListOf` function is deprecated. Migrate to `Fp\Evidence\proveNonEmptyList` and `Fp\Evidence\of` for proving non-empty lists of a specific type. ```php */ function safeDiv(int $dividend, int $divisor): Option { return Option::condLazy(0 !== $divisor, fn() => $dividend / $divisor); } Stream::emits([0, 2]) ->repeat(3) // [0, 2, 0, 2, 0, 2] ->filterMap(fn(int $i) => safeDiv($i, $i)) // [1, 1, 1] ->take(9999) // [1, 1, 1] ->toFile('/dev/null'); ``` -------------------------------- ### Map BC: Replace Entry with KV combinators Source: https://github.com/fp4php/functional/blob/master/UPGRADING-v5.md The `Fp\Collections\Entry` class is removed. Use the new KV (Key-Value) combinators like `mapKV` for operations on `Fp\Collections\Map` that require access to both keys and values. ```php $map->mapKV(fn(string $key, array $row) => new Row(id: $key, data: $row)); ``` -------------------------------- ### Replace Collection::firstOf with firstMap and Evidence::of Source: https://github.com/fp4php/functional/blob/master/UPGRADING-v5.md The `firstOf` method has been removed from collections. Utilize the `firstMap` method along with the `Fp\Evidence\of` function to find the first element of a specific type. ```diff - $seq->firstOf(Foo::class); + $seq->firstMap(of(Foo::class)); ``` -------------------------------- ### NonEmptyLinkedList: Collecting and Folding Elements in PHP Source: https://github.com/fp4php/functional/blob/master/doc/Collections.md Demonstrates the usage of NonEmptyLinkedList in PHP for collecting elements and performing a fold operation. Similar to NonEmptyArrayList, this example creates a non-empty linked list, maps to extract integer values from Foo objects, and then calculates their sum. ```php map(fn(Foo $elem) => $elem->a) ->fold(0)(fn($acc, $elem) => $acc + $elem); ``` -------------------------------- ### Map BC: Replace mapKeys with reindex Source: https://github.com/fp4php/functional/blob/master/UPGRADING-v5.md The `mapKeys` method for `Fp\Collections\Map` has been removed. Use the `reindex` method instead, providing a callable that returns the new key for each element. ```php $map->reindex(fn(Foo $foo) => $foo->a); ``` -------------------------------- ### Get Tail of Collection - fp4php Source: https://github.com/fp4php/functional/blob/master/doc/Functions.md Returns all elements of a collection except for the first one. This is useful for recursive functions or when you need to process a collection starting from the second element. ```php a === $that->a && $this->b === $that->b; } public function hashCode(): string { return md5(implode(',', [$this->a, $this->b])); } } $collection = HashMap::collectPairs([ [new Foo(1), 1], [new Foo(2), 2], [new Foo(3), 3], [new Foo(4), 4] ]); $collection(new Foo(2))->getOrElse(0); // 2 $collection ->map(fn(int $value) => $value + 1) ->filter(fn(int $value) => $value > 2) ->fold(0)(fn(int $acc, int $value) => $acc + $value); // 3+4+5=12 ``` -------------------------------- ### Turn nullable keys to undefined keys with filterNotNull in PHP Source: https://github.com/fp4php/functional/blob/master/doc/Psalm.md This code snippet shows how the `Fp\Collection\filterNotNull` function transforms nullable keys in an array to possibly undefined keys. The example function `example` takes an array with a potentially null `age` and returns an array where `age` is marked as optional (`age?`), improving type safety for optional properties. ```php */ $maybeFooMaybeNot = Option::do(function() use ($untrusted) { // If $untrusted is not null then bind this value to $notNull $notNull = yield Option::fromNullable($untrusted); // If $notNull is non-empty-list then bind this value to $nonEmptyListOfFoo $nonEmptyList = yield proveNonEmptyList($notNull, of(Foo::class)); // Continue computation if $nonEmptyList contains only one element yield proveTrue(1 === count($nonEmptyList)); // I'm sure it's Foo object return $nonEmptyList[0]; }); // Inferred type is Tests\Mock\Foo $foo = $maybeFooMaybeNot->getOrCall(fn() => new Foo(0)); ``` -------------------------------- ### Get collection keys (PHP) Source: https://github.com/fp4php/functional/blob/master/src/Doc/Md/Functions/2_Collection.md The 'keys' function extracts and returns a list of all keys present in a collection. ```php 1, 'b' => 2]); // ['a', 'b'] ``` -------------------------------- ### Collection::toHashMap signature change Source: https://github.com/fp4php/functional/blob/master/UPGRADING-v5.md The signature of the `toHashMap` method in collections has changed. It now requires no arguments and has an added `@psalm-if-this-is` annotation. ```diff - $seq->toHashMap($i => [$i->key, $i]); + $seq->toHashMap(); ``` -------------------------------- ### Parse Configuration with Option and N Combinators in PHP Source: https://context7.com/fp4php/functional/llms.txt Parses and validates configuration data using Option's do-notation and sequenceOptionT, then constructs a Config object using mapN and a constructor. This pattern is useful for handling potentially missing or invalid input data safely. ```php at($data, 'host')->flatMap(proveString(...)), fn() => at($data, 'port')->flatMap(proveInt(...)), fn() => at($data, 'ssl')->flatMap(proveBool(...)), ); return $validated; })->mapN(ctor(Config::class)); // Option ``` -------------------------------- ### PartitionMap for Collecting Errors (PHP) Source: https://github.com/fp4php/functional/blob/master/doc/Monads.md Shows how to use `partitionMap` combined with `toEither` to collect all errors from operations returning Either. This is useful when you want to process a collection and gather all failure cases into a single Either result. ```php , ArrayList> // Result is Left(ArrayList('6 is greater than 5', '7 is greater than 5')) $result = ArrayList::collect([1, 2, 3, 4, 5, 6, 7]) ->partitionMap( fn($i) => $i > 5 ? Either::left("{$i} is greater than 5") : Either::right($i), ) ->toEither(); ``` -------------------------------- ### Set BC: Replace updated with appended Source: https://github.com/fp4php/functional/blob/master/UPGRADING-v5.md The `updated` method for `Fp\Collections\Set` has been removed. Use the `appended` method to add an element to the set. ```php $set->appended(new Foo(a: 42)); ``` -------------------------------- ### Tuple Unpacking with mapN in PHP Source: https://context7.com/fp4php/functional/llms.txt Demonstrates simple tuple unpacking using mapN with Option. It takes an array of integers, unpacks them into individual arguments for a callback function, and returns the sum. ```php $result = Option::some([1, 2, 3]) ->mapN(fn(int $a, int $b, int $c) => $a + $b + $c); // Some(6) ``` -------------------------------- ### Option BC: Replace condLazy with when Source: https://github.com/fp4php/functional/blob/master/UPGRADING-v5.md The `condLazy` method for `Fp\Functional\Option\Option` has been removed. Use the `when` method with a callable for lazy evaluation of the conditional action. ```php \Fp\Functional\Option\Option::when(getTrue(), fn() => doSomething()); ``` -------------------------------- ### PHP Do-notation for Option Chaining Source: https://github.com/fp4php/functional/blob/master/src/Doc/Md/Monads/3_DoNotation.md This snippet demonstrates the use of do-notation in PHP to chain multiple Option-returning functions. It simplifies the process of handling potential null or empty values at each step of a computation. The example shows fetching user data, their first order, the tracking number, and finally the tracking status, all within a single Option::do block. ```php */ function getUserById(int $id): Option {} /** * @return Option */ function getUserFirstOrder(User $user): Option {} /** * @return Option */ function getOrderTrackNumber(Order $order): Option {} /** * @return Option */ function getTrackingStatus(TrackingNumber $trackingNumber): Option {} /** * @var string $status */ $status = Option::do(function () { $user = yield getUserById(654); $order = yield getUserFirstOrder($user); $trackNumber = yield getOrderTrackNumber($order); return yield getTrackingStatus($trackNumber); })->getOrElse('no status info'); ``` -------------------------------- ### Option BC: Replace isNonEmpty with isSome Source: https://github.com/fp4php/functional/blob/master/UPGRADING-v5.md The `isNonEmpty` method for `Fp\Functional\Option\Option` has been removed. Use `isSome` to determine if an Option contains a value. ```php $option->isSome(); ``` -------------------------------- ### PHP Collection: Replace firstOf with firstMap and of in PHP Source: https://github.com/fp4php/functional/blob/master/UPGRADING-v5.md The `Fp\Collection\firstOf` function has been removed. Use `Fp\Collection\firstMap` in conjunction with `Fp\Evidence\of` to achieve the same result. ```php $list * @return Option> */ ``` -------------------------------- ### Replace Stream::repeatN with Stream::repeat Source: https://github.com/fp4php/functional/blob/master/UPGRADING-v5.md The `repeatN` method has been removed from `Fp\Streams\Stream`. Use the `repeat` method with the `$times` parameter to achieve the same functionality. ```diff - $stream->repeatN(2); + $stream->repeat(2); ``` -------------------------------- ### Either Monad: Handling Success and Failure in PHP Source: https://context7.com/fp4php/functional/llms.txt Illustrates the Either monad for computations that can result in either a success (Right) or a failure (Left). Covers creation, conditional logic, exception handling, transformations (map, mapLeft, flatMap), value extraction, and error handling with orElse. ```php 'success', fn() => 'error' ); // Right('success') // Exception handling with mapping $result = Either::try( fn() => riskyOperation(), fn(Throwable $e) => $e->getMessage() ); // Left('error message') or Right(value) // Transformations $processed = Either::right(10) ->map(fn(int $x) => $x * 2) // Right(20) ->mapLeft(fn($err) => "Error: $err") ->flatMap(fn(int $x) => $x > 15 ? Either::right($x) : Either::left('too small')); // Right(20) // Extracting values $value = Either::right(42)->get(); // 42 $value = Either::left('err')->get(); // 'err' $value = Either::left('err')->getOrElse(0); // 0 $value = Either::left('err')->getOrCall(fn($e) => strlen($e)); // 3 // Error handling with orElse $result = Either::left('first error') ->orElse(fn() => Either::left('second error')) ->orElse(fn() => Either::right('recovered')); // Right('recovered') // Convert to Option $option = Either::right(42)->toOption(); // Some(42) $option = Either::left('err')->toOption(); // None // Filter with error $filtered = Either::right(5) ->filterOrElse( fn(int $x) => $x > 10, fn(int $x) => "Value $x is too small" ); // Left('Value 5 is too small') ``` -------------------------------- ### Replace Stream::toAssocArray with Stream::toArray Source: https://github.com/fp4php/functional/blob/master/UPGRADING-v5.md The `toAssocArray` method has been removed from `Fp\Streams\Stream`. Use `toArray` instead for converting streams to associative arrays. ```diff - $stream->toAssocArray(); + $stream->toArray(); ``` -------------------------------- ### Option BC: Replace filterOf with flatMap and of Source: https://github.com/fp4php/functional/blob/master/UPGRADING-v5.md The `filterOf` method on `Fp\Functional\Option\Option` has been removed. Use `flatMap` in conjunction with `Fp\Evidence\of` to achieve the same filtering functionality. ```php $option->flatMap(of(Foo::class)); ``` -------------------------------- ### PHP String: Move regExpMatch from Fp\String to Fp\Util Source: https://github.com/fp4php/functional/blob/master/UPGRADING-v5.md The `regExpMatch` function has been relocated from `Fp\String` to `Fp\Util`. Ensure your code references the new location. ```php [0-9]+)/', 'aa1123'); // After \Fp\Util\regExpMatch('/[a-z]+(?[0-9]+)/', 'aa1123'); ``` -------------------------------- ### Create and Transform Infinite Streams in PHP Source: https://github.com/fp4php/functional/blob/master/doc/Streams.md Demonstrates creating an infinite stream, applying transformations like map and take, and collecting the results into a list. This showcases lazy evaluation and stream immutability. ```php repeat() // [1, 1, ...] infinite stream ->map(fn(int $i) => $i + 1) // [2, 2, ...] infinite stream ->take(5) // [2, 2, 2, 2, 2] ->toList(); // [2, 2, 2, 2, 2] ``` -------------------------------- ### PHP JSON: Move jsonDecode from Fp\Json to Fp\Util Source: https://github.com/fp4php/functional/blob/master/UPGRADING-v5.md The `jsonDecode` function has been moved from the `Fp\Json` namespace to `Fp\Util`. Update your import statements accordingly. ```php Option::when($i % 2, fn() => $i)); // After \Fp\Collection\traverseOption($collection, fn($i) => Option::when($i % 2, fn() => $i)); ``` -------------------------------- ### Option Monad: Handling Optional Values in PHP Source: https://context7.com/fp4php/functional/llms.txt Demonstrates the usage of the Option monad for representing optional values, avoiding null checks. It covers creation, conditional logic, safe exception handling, transformations (map, filter, flatMap), value extraction, and chaining with orElse. ```php 'value'); // Some('value') $option = Option::when(false, fn() => 'value'); // None // Safe exception handling $result = Option::try(fn() => json_decode('invalid', flags: JSON_THROW_ON_ERROR)); // => None (exception converted to None) $result = Option::try(fn() => json_decode('{"a":1}', true)); // => Some(['a' => 1]) // Transformations $mapped = Option::some(5) ->map(fn(int $x) => $x * 2) // Some(10) ->filter(fn(int $x) => $x > 5) // Some(10) ->flatMap(fn(int $x) => Option::some($x + 1)); // Some(11) // Extracting values $value = Option::some(42)->get(); // 42 $value = Option::none()->get(); // null $value = Option::none()->getOrElse(0); // 0 $value = Option::none()->getOrCall(fn() => computeDefault()); // lazy default // Chaining with orElse $result = Option::none() ->orElse(fn() => Option::none()) ->orElse(fn() => Option::some('fallback')); // Some('fallback') // First match from collection $first = Option::first([ Option::none(), fn() => Option::none(), // lazy evaluation fn() => Option::some(42), // returns this fn() => Option::some(43), // never evaluated ]); // Some(42) ``` -------------------------------- ### PHP Collection: Replace lastOf with lastMap and of in PHP Source: https://github.com/fp4php/functional/blob/master/UPGRADING-v5.md The `Fp\Collection\lastOf` function is no longer available. Utilize `Fp\Collection\lastMap` combined with `Fp\Evidence\of` for equivalent functionality. ```php $result */ $result = at([new Foo(), 2, 3], 1); ``` ### Response #### Success Response (Option) - **Option**: Contains the element if found, otherwise None. #### Response Example ```php // Example output depends on the element at index 1 ``` ``` -------------------------------- ### Simulate First-Class Callable for Constructors with ctor in PHP Source: https://github.com/fp4php/functional/blob/master/doc/Psalm.md This PHP snippet demonstrates how to use the `Fp\Callable\ctor` function to simulate first-class callable behavior for class constructors, which is not natively supported in PHP 8.1. It requires a plugin for static analysis. ```php $i instanceof Foo); ``` -------------------------------- ### PHP Collection: Replace existsOf with exists in PHP Source: https://github.com/fp4php/functional/blob/master/UPGRADING-v5.md The `Fp\Collection\existsOf` function has been removed. Use `Fp\Collection\exists` with a closure that checks the instance type instead. ```php $i instanceof Foo); ``` -------------------------------- ### Timed Stream Emission and Output in PHP Source: https://github.com/fp4php/functional/blob/master/src/Doc/Md/Streams/1_Overview.md Shows how to create a stream that emits a value every specified interval (e.g., 5 seconds), maps these emissions to descriptive strings, and then prints each element to standard output as a line. This is useful for periodic tasks or monitoring. ```php map(fn(int $elapsed) => "$elapsed seconds elapsed from stream start") ->lines(); // print element every 5 seconds to stdout ``` -------------------------------- ### Map BC: Rename updated to appended Source: https://github.com/fp4php/functional/blob/master/UPGRADING-v5.md The `updated` method in `Fp\Collections\Map` has been renamed to `appended`. Use `appended` to add or update a key-value pair in the map. ```php $map->appended($key, $value); ``` -------------------------------- ### PHP Callable Utilities: Composition and Partial Application Source: https://context7.com/fp4php/functional/llms.txt Demonstrates fp4php's callable utilities, including function composition (compose), partial application (partial, partialRight), constructor callable (ctor), and piping. These functions enhance the way functions and methods can be manipulated and applied. ```php (string) $x; $stringToFloat = fn(string $x): float => (float) $x; $composed = compose($intToString, $stringToFloat); // int -> float // Partial application (left) $add = fn(int $a, int $b, int $c): int => $a + $b + $c; $add10 = partial($add, 10); // fn($b, $c) => 10 + $b + $c $result = $add10(5, 3); // 18 // Partial application (right) $greet = fn(string $greeting, string $name): string => "$greeting, $name!"; $sayHello = partialRight($greet, 'World'); $result = $sayHello('Hello'); // 'Hello, World!' // Constructor as callable class User { public function __construct( public string $name, public int $age ) {} } $createUser = ctor(User::class); $user = $createUser('Alice', 30); // Use with mapN Option::some(['Alice', 30])->mapN(ctor(User::class)); // Some(User) ``` -------------------------------- ### Option BC: Replace cond and unless with when Source: https://github.com/fp4php/functional/blob/master/UPGRADING-v5.md The `cond` and `unless` methods on `Fp\Functional\Option\Option` are removed. Use the `when` method for conditional execution, providing a predicate and a callable. ```php \Fp\Functional\Option\Option::when(getTrue(), fn() => doSomething()); ``` ```php \Fp\Functional\Option\Option::when(!getFalse(), fn() => doSomething()); ``` -------------------------------- ### Implement assertion effect for proveTrue in PHP Source: https://github.com/fp4php/functional/blob/master/doc/Psalm.md This code illustrates the implementation of an assertion effect for `Fp\Evidence\proveTrue`, similar to PHP's built-in `assert` function. It uses `Option::do` to demonstrate how `proveTrue` can be used to narrow down types within a functional context, ensuring type safety after the assertion. ```php getOrCall(fn() => throw new RuntimeExeption()); ``` -------------------------------- ### PHP Collection: Replace reduce with fold in PHP Source: https://github.com/fp4php/functional/blob/master/UPGRADING-v5.md The `Fp\Collection\reduce` function has been removed. Use `Fp\Collection\fold` instead, providing an initial value and a folding closure. ```php $acc + $cur)->getOrElse(0); // After \Fp\Collection\fold($collection, 0)(fn($acc, $cur) => $acc + $cur); ``` -------------------------------- ### Type Assertions with Option Monad and Do-Notation (PHP) Source: https://github.com/fp4php/functional/blob/master/doc/Monads.md Demonstrates type assertions using the Option monad and a do-notation implementation with PHP generators. It shows how to safely extract and assert types from potentially null or untrusted data, inferring types at each step. ```php */ $maybeFooMaybeNot = Option::do(function() use ($untrusted) { $notNull = yield Option::fromNullable($untrusted); yield proveTrue(is_array($notNull)); // Inferred type is array $list = yield proveList($notNull); // Inferred type is list $nonEmptyList = yield proveNonEmptyList($list); // Inferred type is non-empty-list $nonEmptyListOfFoo = yield proveNonEmptyList($nonEmptyList, of(Foo::class)); // Inferred type is non-empty-list $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)) ```