/var/www/hkosl.com/littleark/webadmin/libraies/guzzlehttp/promises/src/Coroutine.php


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
<?php
namespace GuzzleHttp\Promise;

use 
Exception;
use 
Generator;
use 
Throwable;

/**
 * Creates a promise that is resolved using a generator that yields values or
 * promises (somewhat similar to C#'s async keyword).
 *
 * When called, the coroutine function will start an instance of the generator
 * and returns a promise that is fulfilled with its final yielded value.
 *
 * Control is returned back to the generator when the yielded promise settles.
 * This can lead to less verbose code when doing lots of sequential async calls
 * with minimal processing in between.
 *
 *     use GuzzleHttp\Promise;
 *
 *     function createPromise($value) {
 *         return new Promise\FulfilledPromise($value);
 *     }
 *
 *     $promise = Promise\coroutine(function () {
 *         $value = (yield createPromise('a'));
 *         try {
 *             $value = (yield createPromise($value . 'b'));
 *         } catch (\Exception $e) {
 *             // The promise was rejected.
 *         }
 *         yield $value . 'c';
 *     });
 *
 *     // Outputs "abc"
 *     $promise->then(function ($v) { echo $v; });
 *
 * @param callable $generatorFn Generator function to wrap into a promise.
 *
 * @return Promise
 * @link https://github.com/petkaantonov/bluebird/blob/master/API.md#generators inspiration
 */
final class Coroutine implements PromiseInterface
{
    
/**
     * @var PromiseInterface|null
     */
    
private $currentPromise;

    
/**
     * @var Generator
     */
    
private $generator;

    
/**
     * @var Promise
     */
    
private $result;

    public function 
__construct(callable $generatorFn)
    {
        
$this->generator $generatorFn();
        
$this->result = new Promise(function () {
            while (isset(
$this->currentPromise)) {
                
$this->currentPromise->wait();
            }
        });
        
$this->nextCoroutine($this->generator->current());
    }

    public function 
then(
        
callable $onFulfilled null,
        
callable $onRejected null
    
) {
        return 
$this->result->then($onFulfilled$onRejected);
    }

    public function 
otherwise(callable $onRejected)
    {
        return 
$this->result->otherwise($onRejected);
    }

    public function 
wait($unwrap true)
    {
        return 
$this->result->wait($unwrap);
    }

    public function 
getState()
    {
        return 
$this->result->getState();
    }

    public function 
resolve($value)
    {
        
$this->result->resolve($value);
    }

    public function 
reject($reason)
    {
        
$this->result->reject($reason);
    }

    public function 
cancel()
    {
        
$this->currentPromise->cancel();
        
$this->result->cancel();
    }

    private function 
nextCoroutine($yielded)
    {
        
$this->currentPromise promise_for($yielded)
            ->
then([$this'_handleSuccess'], [$this'_handleFailure']);
    }

    
/**
     * @internal
     */
    
public function _handleSuccess($value)
    {
        unset(
$this->currentPromise);
        try {
            
$next $this->generator->send($value);
            if (
$this->generator->valid()) {
                
$this->nextCoroutine($next);
            } else {
                
$this->result->resolve($value);
            }
        } catch (
Exception $exception) {
            
$this->result->reject($exception);
        } catch (
Throwable $throwable) {
            
$this->result->reject($throwable);
        }
    }

    
/**
     * @internal
     */
    
public function _handleFailure($reason)
    {
        unset(
$this->currentPromise);
        try {
            
$nextYield $this->generator->throw(exception_for($reason));
            
// The throw was caught, so keep iterating on the coroutine
            
$this->nextCoroutine($nextYield);
        } catch (
Exception $exception) {
            
$this->result->reject($exception);
        } catch (
Throwable $throwable) {
            
$this->result->reject($throwable);
        }
    }
}