1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace mpyw\Co\Internal; |
4
|
|
|
use mpyw\Co\CoInterface; |
5
|
|
|
|
6
|
|
|
class GeneratorContainer |
7
|
|
|
{ |
8
|
|
|
/** |
9
|
|
|
* Generator. |
10
|
|
|
* @var \Generator |
11
|
|
|
*/ |
12
|
|
|
private $g; |
13
|
|
|
|
14
|
|
|
/** |
15
|
|
|
* Generator object hash. |
16
|
|
|
* @var string |
17
|
|
|
*/ |
18
|
|
|
private $h; |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* Thrown exception. |
22
|
|
|
* @var \Throwable|\Exception |
23
|
|
|
*/ |
24
|
|
|
private $e; |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* Parent yield key. |
28
|
|
|
* @var mixed |
29
|
|
|
*/ |
30
|
|
|
private $yieldKey; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* Constructor. |
34
|
|
|
* @param \Generator $g |
35
|
|
|
*/ |
36
|
43 |
|
public function __construct(\Generator $g, $yield_key = null) |
37
|
43 |
|
{ |
38
|
43 |
|
$this->g = $g; |
39
|
43 |
|
$this->h = spl_object_hash($g); |
40
|
43 |
|
$this->yieldKey = $yield_key; |
41
|
43 |
|
$this->valid(); |
42
|
43 |
|
} |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* Return parent yield key. |
46
|
|
|
* @return mixed |
47
|
|
|
*/ |
48
|
28 |
|
public function getYieldKey() |
49
|
28 |
|
{ |
50
|
28 |
|
return $this->yieldKey; |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* Return generator hash. |
55
|
|
|
* @return string |
56
|
|
|
*/ |
57
|
29 |
|
public function __toString() |
58
|
29 |
|
{ |
59
|
29 |
|
return $this->h; |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* Return whether generator is actually working. |
64
|
|
|
* @return bool |
65
|
|
|
*/ |
66
|
43 |
|
public function valid() |
67
|
43 |
|
{ |
68
|
|
|
try { |
69
|
43 |
|
$this->g->current(); |
70
|
43 |
|
return $this->e === null && $this->g->valid() && $this->g->key() !== CoInterface::RETURN_WITH; |
71
|
2 |
|
} catch (\Throwable $e) {} catch (\Exception $e) {} |
72
|
2 |
|
$this->e = $e; |
73
|
2 |
|
return false; |
74
|
|
|
} |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* Return current key. |
78
|
|
|
* @return mixed |
79
|
|
|
*/ |
80
|
33 |
|
public function key() |
81
|
33 |
|
{ |
82
|
33 |
|
$this->validateValidity(); |
83
|
33 |
|
return $this->g->key(); |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* Return current value. |
88
|
|
|
* @return mixed |
89
|
|
|
*/ |
90
|
35 |
|
public function current() |
91
|
35 |
|
{ |
92
|
35 |
|
$this->validateValidity(); |
93
|
35 |
|
return $this->g->current(); |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
/** |
97
|
|
|
* Send value into generator. |
98
|
|
|
* @param mixed $value |
99
|
|
|
* @NOTE: This method returns nothing, |
100
|
|
|
* while original generator returns something. |
101
|
|
|
*/ |
102
|
31 |
View Code Duplication |
public function send($value) |
|
|
|
|
103
|
31 |
|
{ |
104
|
31 |
|
$this->validateValidity(); |
105
|
|
|
try { |
106
|
31 |
|
$this->g->send($value); |
107
|
28 |
|
return; |
108
|
19 |
|
} catch (\Throwable $e) {} catch (\Exception $e) {} |
109
|
19 |
|
$this->e = $e; |
110
|
19 |
|
} |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* Throw exception into generator. |
114
|
|
|
* @param \Throwable|\Exception $e |
115
|
|
|
* @NOTE: This method returns nothing, |
116
|
|
|
* while original generator returns something. |
117
|
|
|
*/ |
118
|
19 |
View Code Duplication |
public function throw_($e) |
|
|
|
|
119
|
19 |
|
{ |
120
|
19 |
|
$this->validateValidity(); |
121
|
|
|
try { |
122
|
19 |
|
$this->g->throw($e); |
123
|
15 |
|
return; |
124
|
13 |
|
} catch (\Throwable $e) {} catch (\Exception $e) {} |
125
|
13 |
|
$this->e = $e; |
126
|
13 |
|
} |
127
|
|
|
|
128
|
|
|
/** |
129
|
|
|
* Return whether Throwable is thrown. |
130
|
|
|
* @return bool |
131
|
|
|
*/ |
132
|
31 |
|
public function thrown() |
133
|
31 |
|
{ |
134
|
31 |
|
return $this->e !== null; |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
/** |
138
|
|
|
* Return value that generator has returned or thrown. |
139
|
|
|
* @return mixed |
140
|
|
|
*/ |
141
|
34 |
|
public function getReturnOrThrown() |
142
|
34 |
|
{ |
143
|
34 |
|
$this->validateInvalidity(); |
144
|
33 |
|
if ($this->e === null && $this->g->valid() && !$this->valid()) { |
145
|
9 |
|
return $this->g->current(); |
146
|
|
|
} |
147
|
32 |
|
if ($this->e) { |
148
|
23 |
|
return $this->e; |
149
|
|
|
} |
150
|
29 |
|
return method_exists($this->g, 'getReturn') ? $this->g->getReturn() : null; |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
/** |
154
|
|
|
* Validate that generator has finished running. |
155
|
|
|
* @throws \BadMethodCallException |
156
|
|
|
*/ |
157
|
36 |
|
private function validateValidity() |
158
|
36 |
|
{ |
159
|
36 |
|
if (!$this->valid()) { |
160
|
2 |
|
throw new \BadMethodCallException('Unreachable here.'); |
161
|
|
|
} |
162
|
36 |
|
} |
163
|
|
|
|
164
|
|
|
/** |
165
|
|
|
* Validate that generator is still running. |
166
|
|
|
* @throws \BadMethodCallException |
167
|
|
|
*/ |
168
|
34 |
|
private function validateInvalidity() |
169
|
34 |
|
{ |
170
|
34 |
|
if ($this->valid()) { |
171
|
1 |
|
throw new \BadMethodCallException('Unreachable here.'); |
172
|
|
|
} |
173
|
33 |
|
} |
174
|
|
|
} |
175
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.