smscr/simple-coroutine-for-reactphp

1.0.1 2019-09-15 23:07 UTC

This package is auto-updated.

Last update: 2022-06-16 22:44:57 UTC


README

Description

The function coroutine accepts as an argument $resolvable value and resolves it as callable or promose with support for yield from instances of \Generator, and returns a promise either resolved with the final value that cannot be resolved further or rejected with the first \Throwable that wasn't caught in the chain

Install via composer:

"require": {
   "smscr/simple-coroutine-for-reactphp": "^1.0.0"
}

Details:

The first argument of the function is $resolvable value

If second argument $call = true, then would be attempted first to resolve (through possible Promise chains) the $resolvable value to a callable. If a callable is detected, it is invoked and it's return value is resolved (through possible Promise chains). This applies recursively.

If $resolvable is a Generator, or a Generator is found by resolving $resolvable or by resolving a result of invoked callable, then the Generator is processed as a coroutine

If the $resolvable is an array, then it would be mapped to resolved values, including, if $call = true, then all entries of the array will be attempted to resolve to a callable or a Generator, each, independently, and this applies recursively.

When a Generator is processed as a coroutine, this function is applied to any value yielded by a Generator, that means, a callable (if $call = true), a Generator, a Promise or an array of any of such will be resolved by the rules above if yielded by a Generator resolved by the rules above

After the value yielded by a Generator is resolved, the result is sent to the Generator If any errors occur during resolving a value, it is thrown into a Generator Once a Generator returns a value, it is resolved by the rules above

The resolved value that was returned by a Generator is a result of the Promise returned by this function, possibly as an element of an array of such results

Usage:

use React\Promise;
use React\Promise\PromiseInterface;
use function Shavshukov\Coroutine\coroutine;

function resolvePromises(PromiseInterface $promise1, PromiseInterface $promise2, PromiseInterface $promise3, callable $resultsCallback)
{
    try {
        // instead of Promise\resolve($promise1)->then(function ($result1) {...});
        $result1 = yield $promise1;
        
        // instead of Promise\all([$promise2, $promise3])->then(function ($results23) {...});
        $results23 = yield [
            $promise2,
            $promise3
        ];
        
        $generator = function () use ($result1, $results23) {
            $results = [];
            
            $results[] = yield $result1;
            foreach ($results23 as $result) {
                $results[] = yield $result;
            }
            
            return $results;
        };
        
        // coroutine will call this generator function and resolve it
        $results123 = yield $generator;
        
        // if you pass a \Generator instance it will also resolve it
        $onceMoreResults123 = yield $generator();
        
        // if a PromiseInterface resolves to a \Generator, it will also resolve the \Generator value
        // this would also work with array of promises that resolve to \Generators
        // and this would work recursively
        $secondTimeMoreResults123 = yield Promise\resolve()->then(function () use ($generator) {
             return $generator();
        });
        
        // values will be passed to the $resultsCallback, not promises or \Generator instances
        $finalResult = yield $resultsCallback($secondTimeMoreResults123);
        
        return $finalResult;
    } catch (\Throwable $e) {
        // return an exception if caught
        return $e;
    }
}

// coroutine function accepts promises, values, \Generator instances and arrays of such, and always returns a promise
coroutine(function () {
    $return = yield resolvePromises(Promise\resolve(1), Promise\resolve(2), Promise\resolve(3), function (array $secondTimeMoreResults123) {
        return implode(', ', $secondTimeMoreResults123);
    });
    
    return $return;
})->then(function (string $finalResult1) {
    // will print 1, 2, 3
    echo $finalResult1 . PHP_EOL;
});

coroutine(function () {
    $return = yield resolvePromises(Promise\resolve(1), Promise\resolve(2), Promise\resolve(3), function (array $secondTimeMoreResults123) {
        throw new \Exception('Sometines, something happens...');
    });
    
    return $return;
})->then(function (\Throwable $exception) {
    // will print "Something happened! Sometines, something happens..."
    echo "Something happened! {$exception->getMessage()}" . PHP_EOL;
});